[
  {
    "path": ".build.yml",
    "content": "image: ubuntu/lts\npackages:\n  - meson\n  - ninja-build\n  - autoconf\n  - automake\n  - build-essential\n  - libpango1.0-dev\n  - libstartup-notification0-dev\n  - libxcb-ewmh-dev\n  - libxcb-icccm4-dev\n  - libxcb-randr0-dev\n  - libxcb-util0-dev\n  - libxcb-xinerama0-dev\n  - libxcb-xkb-dev\n  - libxcb-xrm-dev\n  - libxcb-cursor-dev\n  - libxcb-imdkit-dev\n  - libxcb-keysyms1\n  - libxkbcommon-dev\n  - libxkbcommon-dev\n  - libxkbcommon-x11-dev\n  - libgdk-pixbuf2.0-dev\n  - ninja-build\n  - pandoc\n  - check\n  - flex\n  - bison\n  - libglib2.0-dev-bin\n  - doxygen\nsources:\n  - https://sr.ht/~qball/rofi/\ntasks:\n  - setup: |\n     cd rofi\n     meson setup builddir . -Db_lto=true\n  - build: |\n     ninja -C rofi/builddir\n  - test: |\n     ninja -C rofi/builddir test\n  - doxygen: |\n     ninja -C rofi/builddir/ doc/html > doxygen.log 2>&1\n     if [ $(grep -c warnings doxygen.log) -gt 0 ]; then exit 1; fi \n  - dist: |\n     ninja -C rofi/builddir dist\nartifacts:\n  - rofi/builddir/meson-dist/rofi-1.7.8-dev.tar.xz\n"
  },
  {
    "path": ".clang-tidy",
    "content": "Checks: -clang-analyzer-optin.core.EnumCastOutOfRange\n"
  },
  {
    "path": ".gitattributes",
    "content": ".build.yml export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n.mailmap export-ignore\n.github export-ignore\n.gitlab-ci.yml export-ignore\n.gitmodules export-ignore\n.travis.yml export-ignore\nreleasenotes export-ignore\ndoc/*.png export-ignore\ndoc/help-output.txt export-ignore\ndoc/sizing.svg export-ignore\ndoc/Notes export-ignore\ndoc/old-theme-convert-output.rasi export-ignore\ndoc/test_xr.txt export-ignore\ndoc/create_screenshot.sh export-ignore\nmkdocs export-ignore\nscript/*.jpg export-ignore\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "When reporting bugs keep in mind that the people working on it do this unpaid,\nin their free time and as a hobby. So be polite and helpful. Reports that\ndemand, contain insults to this or other projects, or have a general unfriendly\ntone will be closed without discussion. Everybody has it own way of working;\nWhat might be the norm for you, might not be for others. Therefore be verbose in\nyour description.\n\n**The issue tracker is for bugs only.**\n\nThis is an attempt to keep the issue tracker clean and searchable.\n\nQuestions or discussions about new features belong on\n[GITHUB Discussions](https://github.com/davatorium/rofi/discussions) or\n[FORUM](https://reddit.com/r/qtools/),\n[IRC](https://webchat.freenode.net/?channels=#rofi), frequently asked questions\nwill be added to the [F.A.Q](https://github.com/DaveDavenport/rofi/wiki#faq) on\nthe [wiki](https://github.com/DaveDavenport/rofi/wiki).\n\nQuestions filled in on the bug tracker will be marked `question`, locked and\nclosed.\n\nIt is preferred to have feature requests discussed via\n[GITHUB Discussions](https://github.com/davatorium/rofi/discussions) or\n[FORUM](https://reddit.com/r/qtools/) or\n[IRC](https://webchat.freenode.net/?channels=#rofi) first.\n\n# Creating a bug report\n\nPlease write your bug reports in clear English.\n\nBefore creating a bug report:\n\n* Update to the latest version. Check if problem still exists.\n* Check existing bug reports, see if it is already reported.\n* Read the documentation. Make sure the behaviour you are seeing is a bug.\n\nWhen reporting bugs include the following information:\n\n* Rofi version. rofi -v\n* Rofi configuration. rofi -help (in a [gist](https://gist.github.com/))\n* Steps to reproduce.\n* What behaviour you see.\n* What behaviour you expect to see.\n* A proper title for others to search for.\n* Be exact.\n\nWhen adding comments to an issue make sure:\n\n* It is relevant to the issue.\n* It contributes to solving the issue.\n* Use :+1: :-1: emojis instead of replying 'me too' or 'I also have this.'\n* Do **NOT** ask for an update. Asking does not contribute to solving the issue\n  and just annoys people with a notification. The answer is already available;\n  if there is an update it will be linked/mentioned in the issue, otherwise\n  there is no update.\n\nIssue high-jacking, e.g. adding a request/issue to an existing issue, is very\ndisruptive.\nPlease create a new issue, if it is similar it will be marked duplicate.\n\n# Creating a feature request\n\nBefore creating a feature request:\n\n* First check the *next* branch, to see if the feature has already been\n  implemented.\n* Check existing reports, see if it is already requested.\n\nWhen reporting a feature request include the following information:\n\n* Rofi version and other information. (rofi -info)\n* A clear description of the feature you want added.\n* A use-case for the feature.\n\nIf possible try to explain how you would expect to use feature.\nFor example, should it be a configuration option or a hot-key.\n\nRequesting a feature is no guarantee it will be added.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: Report a problem in Rofi\nlabels: [bug]\ntitle: \"[BUG] \"\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        First read the\n        [guidelines](https://github.com/DaveDavenport/rofi/blob/next/.github/CONTRIBUTING.md)!\n        This is not optional for any report. People must be able to understand\n        the full context of the report when reading it, at any time.\n\n        If you feel like you “it is simple and requires no explanation”, please\n        consider you’re wrong and still fill the full report. What is clear to\n        you might not be clear to somebody else. Any report missing required\n        informations will be labeled as “Incomplete Report - Please follow the\n        guidelines” and will be closed. If you ask a question, enter dummy\n        information in required fields to get past the checks or in general\n        completely ignore the guidelines, the issue will be closed and locked\n        as spam. This includes filling in 'Distro X defaults', we don't know\n        and cannot keep track of what each distribution ships as a default.\n\n        If you are unsure, please use the\n        [discussion](https://github.com/davatorium/rofi/discussions) forum\n        first. It is easy to upgrade a question to an issue in github.\n\n        If you report problems with speed in rofi, please attach a [timing\n        trace](https://github.com/davatorium/rofi/blob/next/doc/rofi-debugging.5.markdown#timing-traces).\n\n        If you have a problem that only occurs when launching rofi from a keybinding.\n        First check that the environment the keybinding passes to rofi is correct.\n\n  - type: input\n    attributes:\n      label: \"Rofi version (rofi -v or git commit in case of build issue)\"\n      placeholder: \"Version: 1.7.5\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Configuration\"\n      description: |\n        Please use https://gist.github.com and include output of `rofi -info` and `rofi -dump-config`.\n        Anything that is not a link to valid output, will not be accepted.\n      placeholder: \"Gist URL\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Theme\"\n      description: |\n        Please use https://gist.github.com and include output of `rofi -dump-theme`.\n        Anything that is not a link to valid output, will not be accepted.\n      placeholder: \"Gist URL\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Timing report\"\n      description: |\n        Please use https://gist.github.com and include output of your command with G_MESSAGES_DEBUG=Timings set.\n      placeholder: \"Gist URL\"\n    validations:\n      required: false\n  - type: input\n    attributes:\n      label: \"Launch command\"\n      placeholder: \"rofi -show drun\"\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: \"Step to reproduce\"\n      placeholder: |\n        * Step 1\n        * Step 2\n        * ...\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: \"Expected behavior\"\n      description: \"Describe the behavior you expect. May include logs, images, or videos.\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Actual behavior\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Additional information\"\n    validations:\n      required: false\n  - type: checkboxes\n    id: latestversion\n    attributes:\n      label: I've checked if the issue exists in the latest stable release\n      description: I confirm that I verified the issue still exists in the latest stable release.\n      options:\n        - label: \"Yes, I have checked the problem exists in the latest stable version\"\n          required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: discussion forum\n    url: https://github.com/davatorium/rofi/discussions\n    about: Please ask and answer questions here.\n  - name: Rofi IRC channel\n    url: https://web.libera.chat/?channels=#rofi\n    about: Please ask and answer question in real time here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation_report.yml",
    "content": "name: Documentation Bug Report\ndescription: Report a problem in Rofi Documentation\nlabels: [Documentation]\ntitle: \"[Doc] \"\nbody:\n\n  - type: markdown\n    attributes:\n      value: |\n        First read the\n        [guidelines](https://github.com/DaveDavenport/rofi/blob/next/.github/CONTRIBUTING.md)!\n        This is not optional for any report. People must be able to understand\n        the full context of the report when reading it, at any time.\n\n        If you feel like you “it is simple and requires no explanation”, please\n        consider you’re wrong and still fill the full report. Any report\n        missing required informations will be labeled as “Incomplete Report -\n        Please follow the guidelines” and will be closed. If you ask a\n        question, enter dummy information in required fields to get passed the\n        checks or in general completely ignore the guidelines, the issue will\n        be closed and locked as spam.\n\n        If you are unsure, please use the\n        [discussion](https://github.com/davatorium/rofi/discussions) forum\n        first. It is easy to upgrade a question to an issue in github.\n\n        **Please do not submit reports related to wayland, see\n        [here](https://github.com/DaveDavenport/rofi/wiki/Wayland) for more\n        information.**\n\n  - type: input\n    attributes:\n      label: \"Rofi version (rofi -v)\"\n      placeholder: \"Version: 1.7.5\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"URL\"\n      description: \"Please provide a link to the relevant documentation.\"\n      placeholder: \"link to page on https://davatorium.github.io/rofi/ or file on https://github.com/davatorium/rofi/\"\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: \"Explain the issue with the documentation, please be verbose.\"\n      placeholder: |\n        * What am I trying to achieve\n        ..\n        * What instructions are unclear, wrong or missing\n        ..\n        * Suggestions for improving the current documentation\n        ..\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Optional fixed text\"\n      description: \"Suggested new and or improved text for documentation.\"\n    validations:\n      required: false\n  - type: checkboxes\n    id: wayland\n    attributes:\n      label: Using wayland display server protocol\n      description: I have checked and confirm that my issue is not related to running rofi using wayland as display server protocol. See [here](https://github.com/DaveDavenport/rofi/wiki/Wayland) for more        information.\n      options:\n        - label: \"No, my documentation issue is not about running rofi using the wayland display server protocol\"\n          required: true\n  - type: checkboxes\n    id: latestversion\n    attributes:\n      label: I've checked if the issue exists in the latest stable release\n      description: I confirm that I verified the issue still exists in the latest stable release. \n      options:\n        - label: \"Yes, I have checked the problem exists in the latest stable version\"\n          required: false\n      \n\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature Request\ndescription: It'd be cool if rofi did/had/would...\nlabels: Feature Request\ntitle: \"[REQUEST] \"\nbody:\n\n  - type: markdown\n    attributes:\n      value: |\n        First read the [guidelines](https://github.com/DaveDavenport/rofi/blob/next/.github/CONTRIBUTING.md)! This is not optional for any report/question. People must be able to understand the full context of the report when reading it, at any time.\n\n        If you feel like you “just have a simple question”, please consider you’re wrong and still fill the full report. Any report missing these informations will be labeled as “Incomplete Report - Please follow the guidelines” and may not be answered in a timely fashion.\n\n        If you are unsure, please use the [discussion](https://github.com/davatorium/rofi/discussions) forum first. It is easy to upgrade a question to an issue in github.\n\n        **Requesting a feature is no guarantee it will be added.**\n\n  - type: checkboxes\n    id: before-feature-request\n    attributes:\n      label: Before opening a feature request\n      options:\n        - label: I checked the *next* branch to see if the feature has already been implemented\n          required: true\n        - label: I searched existing reports to see if it is already requested.\n          required: true\n  - type: textarea\n    attributes:\n      label: \"What is the user problem or growth opportunity you want to see solved?\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"How do you know that this problem exists today? Why is this important?\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Who will benefit from it?\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Rofi version (rofi -v)\"\n      placeholder: \"Version: 1.6.0\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Configuration & Information\"\n      description: \"Please use https://gist.github.com and include output of `rofi -info`, `rofi -dump-config` and `rofi -dump-theme`.\"\n      placeholder: \"Gist URL\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: \"Additional information\"\n    validations:\n      required: false\n\n"
  },
  {
    "path": ".github/actions/doxycheck/action.yml",
    "content": "name: Doxygen Check\ndescription: Checks for Doxygen warnings\n\nruns:\n  using: composite\n  steps:\n    - id: doxy\n      run: ninja -C builddir doc/html > builddir/doxygen.log 2>&1\n      shell: bash\n    - id: check\n      run: |\n        if [[ \"$(grep -c warning: builddir/doxygen.log)\" != 0 ]]; then\n          echo\n          echo Doxygen warnings found:\n          grep warning builddir/doxygen.log\n          echo\n\n          exit 1\n        fi\n\n        python ./doxy-coverage/doxy-coverage.py builddir/doc/html/xml/\n      shell: bash\n"
  },
  {
    "path": ".github/actions/meson/action.yml",
    "content": "name: Meson Build\ndescription: Builds Rofi using Meson\n\ninputs:\n  cc:\n    description: Compiler to use\n    required: true\n  xcb:\n    description: Enable xcb backend\n    default: enabled\n  wayland:\n    description: Enable wayland backend\n    default: enabled\n\nruns:\n  using: composite\n  steps:\n    - id: pip\n      run: pip install meson ninja\n      shell: bash\n    - id: setup\n      run: meson setup builddir -Dxcb=${{ inputs.xcb }} -Dwayland=${{ inputs.wayland }}\n      shell: bash\n      env:\n        CC: ${{ inputs.cc }}\n    - id: build\n      run: ninja -C builddir\n      shell: bash\n    - id: test\n      run: ninja -C builddir test\n      shell: bash\n"
  },
  {
    "path": ".github/actions/release/action.yml",
    "content": "name: Upload dist\ndescription: Create distribution file and upload to release\n\nruns:\n  using: composite\n  steps:\n    - id: dist\n      run: meson dist -C builddir --include-subprojects --formats xztar,gztar --no-tests\n      shell: bash\n    - id: upload\n      uses: actions/upload-artifact@v4\n      with:\n        name: release_tarballs-${{ github.ref_name }}\n        path: |\n          builddir/meson-dist/*.tar.xz\n          builddir/meson-dist/*.tar.gz\n    - id: create_release\n      uses: softprops/action-gh-release@v2\n      with:\n        draft: true\n        files: |\n          builddir/meson-dist/*.tar.xz\n          builddir/meson-dist/*.tar.gz\n"
  },
  {
    "path": ".github/actions/setup/action.yml",
    "content": "name: CI Build Setup\ndescription: Sets up build dependencies\n\ninputs:\n  xcb:\n    description: Install xcb dependencies\n    default: 'true'\n  wayland:\n    description: Install wayland dependencies\n    default: 'true'\n\nruns:\n  using: composite\n  steps:\n    - id: python\n      uses: actions/setup-python@v4\n      with:\n        python-version: '3.x'\n    - id: apt\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y \\\n          discount \\\n          doxygen \\\n          fluxbox \\\n          gdb \\\n          graphviz \\\n          jq \\\n          lcov \\\n          libpango1.0-dev \\\n          libxkbcommon-dev \\\n          libxkbcommon-dev \\\n          libxkbcommon-x11-dev \\\n          libgdk-pixbuf-2.0-dev \\\n          ninja-build \\\n          pandoc \\\n          python3-pip \\\n          python3-setuptools \\\n          python3-wheel \\\n          texi2html \\\n          texinfo \\\n          xdotool \\\n          xfonts-base \\\n          xterm \\\n          xutils-dev\n      shell: bash\n    - id: doxy\n      run: git clone https://github.com/davatorium/doxy-coverage\n      shell: bash\n    - id: apt-wayland\n      if: ${{ inputs.wayland  == 'true' }}\n      run: |\n        sudo apt-get install -y \\\n          libwayland-dev \\\n          wayland-protocols\n      shell: bash\n    - id: apt-xcb\n      if: ${{ inputs.xcb  == 'true' }}\n      run: |\n        sudo apt-get install -y \\\n          libstartup-notification0-dev \\\n          libxcb-ewmh-dev \\\n          libxcb-icccm4-dev \\\n          libxcb-randr0-dev \\\n          libxcb-util0-dev \\\n          libxcb-xinerama0-dev \\\n          libxcb-xkb-dev \\\n          libxcb-xrm-dev \\\n          libxcb-cursor-dev \\\n          libxcb-imdkit-dev\n      shell: bash\n    - id: check\n      run: |\n        curl -L https://github.com/libcheck/check/releases/download/0.15.2/check-0.15.2.tar.gz | tar xzf -\n        cd check-0.15.2\n        ./configure\n        make\n        sudo make install\n        sudo ldconfig\n      shell: bash\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "> Please follow these steps before submitting your PR:\n>\n> - [ ] This PR targets the `next` branch and not `master`\n> - [ ] If your PR is a work in progress, include [WIP] in its title\n> - [ ] Its commits' summaries are reasonably descriptive\n> - [ ] You've described what this PR addresses below\n> - [ ] You've included links to relevant issues, if any with `#issue_num`\n> - [ ] You've deleted this template\n>\n> Thank you for contributing to rofi! <3\n\nYour description here...\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: CI Build\n\non:\n  push:\n    branches:\n      - next\n    paths-ignore:\n      - \"**.md\"\n      - \"**.markdown\"\n      - \"**.rasi\"\n  pull_request:\n    paths-ignore:\n      - \"**.md\"\n      - \"**.markdown\"\n      - \"**.rasi\"\n\njobs:\n  build-gcc:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          submodules: recursive\n      - uses: ./.github/actions/setup\n      - uses: ./.github/actions/meson\n        with:\n          cc: gcc\n      - uses: ./.github/actions/doxycheck\n  build-clang:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          submodules: recursive\n      - uses: ./.github/actions/setup\n      - uses: ./.github/actions/meson\n        with:\n          cc: clang\n  build-gcc-wayland-only:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        with:\n          submodules: recursive\n      - uses: ./.github/actions/setup\n        with:\n          xcb: false\n      - uses: ./.github/actions/meson\n        with:\n          cc: gcc\n          xcb: disabled\n  build-gcc-xcb-only:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: recursive\n      - uses: ./.github/actions/setup\n        with:\n          wayland: false\n      - uses: ./.github/actions/meson\n        with:\n          cc: gcc\n          wayland: disabled\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ 'next', 'master' ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ 'next' ]\n  schedule:\n    - cron: '59 13 * * 3'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'cpp' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Use only 'java' to analyze code written in Java, Kotlin or both\n        # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both\n        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n      with:\n          submodules: recursive\n\n    - uses: ./.github/actions/setup\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs\n        # queries: security-extended,security-and-quality\n\n    - uses: ./.github/actions/meson\n      with:\n        cc: gcc\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n      with:\n        category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/lock.yml",
    "content": "name: 'Lock Threads'\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n  discussions: write\n\nconcurrency:\n  group: lock-threads\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: dessant/lock-threads@v5\n        with:\n          process-only: 'issues'\n          github-token: ${{ github.token }}\n          issue-inactive-days: '31'\n          exclude-issue-created-before: ''\n          exclude-issue-created-after: ''\n          exclude-issue-created-between: ''\n          exclude-issue-closed-before: ''\n          exclude-issue-closed-after: ''\n          exclude-issue-closed-between: ''\n          include-any-issue-labels: ''\n          include-all-issue-labels: ''\n          exclude-any-issue-labels: ''\n          add-issue-labels: ''\n          remove-issue-labels: ''\n          issue-comment: >\n            This pull request has been automatically locked since there\n            has not been any recent activity after it was closed.\n            Please open a new issue for related bugs.\n          issue-lock-reason: 'resolved'\n          log-output: false\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "on:\n  issues:\n    types: [opened, edited]\n\njobs:\n  auto_close_issues:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v1\n\n      - name: Automatically close issues that don't follow the issue template\n        uses: davatorium/auto-close-issues@v1.0.4\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          issue-close-message: \"@${issue.user.login}: hello! :wave:\\n\\nThis issue is being automatically closed because it does not follow the issue template.\" # optional property\n          closed-issues-label: \"Incomplete Report - Please follow the guidelines\" # optional property\n"
  },
  {
    "path": ".github/workflows/mkdocs.yml",
    "content": "name: Publish docs via GitHub Pages\non:\n  push:\n    branches:\n      - sphinx\n      - next\n\njobs:\n  build:\n    name: Deploy docs\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout master\n        uses: actions/checkout@v1\n\n      - name: Deploy docs\n        uses: mhausenblas/mkdocs-deploy-gh-pages@master\n        env:\n          CONFIG_FILE: mkdocs/mkdocs.yml \n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/publish-release.yml",
    "content": "name: Publish release\n\non:\n  push:\n    tags:\n      - '*'\n\njobs:\n  publish-tarball:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          submodules: recursive\n      - uses: ./.github/actions/setup\n      - uses: ./.github/actions/meson\n        with:\n          cc: gcc\n      - uses: ./.github/actions/release\n"
  },
  {
    "path": ".gitignore",
    "content": "/build*/\n/.cache/\n/.vscode/\n\n# I want to ignore log files\n*.log\n\n# Core files should never be checked in\ncore\n\n# ignore patches too, the code is either checked in or branch.\n*.patch*\n\n# backup files\n*.swp\n*.*~\n*.unc-backup~\n*.unc-backup.md5~\n"
  },
  {
    "path": ".gitlab-ci.yml",
    "content": "before_script:\n    - apt-get update\n    - apt-get install --force-yes -y software-properties-common apt-transport-https\n    - add-apt-repository -y 'deb http://debian.jpleau.ca/ jessie-backports main contrib non-free'\n    - apt-get update -qq\n    - apt-get install --force-yes -y autoconf automake make libx11-dev libpango1.0-dev libcairo2-dev libstartup-notification0-dev libxcb-icccm4-dev libxcb-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libx11-xcb-dev\n    - apt-get install --force-yes -y libxcb1-dev xvfb discount xdotool fluxbox libxkbcommon-dev libxkbcommon-x11-dev libxcb-ewmh-dev xutils-dev libtool lcov libxcb-randr0-dev doxygen python flex bison librsvg2-dev texinfo \n    - git clone --recursive https://github.com/Airblader/xcb-util-xrm.git\n    - cd xcb-util-xrm\n    - ./autogen.sh --prefix=/usr\n    - make\n    - sudo make install\n    - cd -\n    - git clone https://github.com/libcheck/check/ -b 0.11.0\n    - cd check\n    - autoreconf -i\n    - TEX=\"false\" ./configure --prefix=/usr/\n    - make\n    - sudo make install\n    - cd -\n    - git clone https://github.com/alobbs/doxy-coverage\n\nbuild-rofi:\n    script:\n        - git submodule update --init\n        - autoreconf -i\n        - ./configure --enable-gcov\n        - make\n        - make check\n        - make distcheck\n        - make coverage\n        - make doxy\n        - python2 doxy-coverage/doxy-coverage.py doc/html/xml/\n    artifacts:\n        expire_in: 2 weeks\n        paths:\n            - coverage\n            - doc/html\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"libgwater\"]\n\tpath = subprojects/libgwater\n\turl = https://github.com/sardemff7/libgwater\n[submodule \"libnkutils\"]\n\tpath = subprojects/libnkutils\n\turl = https://github.com/sardemff7/libnkutils\n"
  },
  {
    "path": ".mailmap",
    "content": "Morgane Glidic <sardemff7+git@sardemff7.net>\n"
  },
  {
    "path": "AUTHORS",
    "content": "Aaron Ash\nAdrià Farrés\nAnton Löfgren\nAvatar\nbendem\nBenjamin Cremer\nBenjamin R. Haskell\nBruno Braga\nBuglloc\nChris Salzberg\ndaemoni\nDan Beste\nDaniel Hahler\nDanteFireX\nDave Davenport\nDeiwin Sarjas\nDimitar Yordanov\nEdwin Pujols\neigengrau\nEric Engeström\nFangrui Song\nfice-t\nFlorian Franzen\nGabriel Holodak\nGareth Poole\nGeorgios Bitzes\nGreg Fitzgerald\nGuy Hughes\nHexchain Tong\nIan Remmler\nJames Vaughan\nJason Pleau\nJasper Lievisse Adriaanse\nKlemens Schölhorn\nkoppa\nlbonn\nMarcin Sedlak\nmarduk\nMichael Vetter\nMoritz Maxeiner\nNick87720z\nNiklas Haas\nN. Izumi\nPaulo Flabiano Smorigo\nPeter Cannici\nqedi\nMorgane Glidic\nRasmus Steinke\nRaZ0rr-Two\nRoomcays\nseanpringle\nSebastian Reuße\nSimon Hanna\nStanislav Seletskiy\nThomas Adam\nThorsten Wißmann\nTilman Blumenbach\nTobias Kortkamp\nTom Hinton\nTonCherAmi\nvimeitor\nWieland Hoffmann\nYaroslav\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at qball@gmpclient.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONFIG.md",
    "content": "> This page does not describe all of **ROFI**'s configuration options, just the\n> most common usecase. For the full configuration options, check the manpages.\n\n<br />\n\n## Where does the configuration live\n\nRofi's configurations, custom themes live in `${XDG_CONFIG_HOME}/rofi/`, on\nmost systems this is `~/.config/rofi/`.\n\nThe name of the main configuration file is `config.rasi`. (`~/.config/rofi/config.rasi`).\n\n## Create an empty configuration file\n\nOpen `~/.config/rofi/config.rasi` in your favorite text editor and add the\nfollowing block:\n\n```css\nconfiguration {\n\n}\n```\n\nYou can now set the options in the `configuration` block.\n\n## Create a configuration file from current setup\n\nIf you do not want to start from scratch, or want to migrate from older\nconfiguration format, you can get tell rofi to dumps it configuration:\n\n```bash\nrofi -dump-config > ~/.config/rofi/config.rasi\n```\n\nThis will have all the possible settings and their current value.\nIf a value is the default value, the entry will be commented.\n\nFor example:\n\n```css\nconfiguration {               \n/*  modes: \"window,run,ssh,drun\";*/\n/*  font: \"mono 12\";*/\n/*  location: 0;*/\n/*  yoffset: 0;*/\n/*  xoffset: 0;*/\n/*  fixed-num-lines: true;*/\n... cut ...\n/*  ml-row-down: \"ScrollDown\";*/                                                                                        \n/*  me-select-entry: \"MousePrimary\";*/                                                                                  \n/*  me-accept-entry: \"MouseDPrimary\";*/                                                                                 \n/*  me-accept-custom: \"Control+MouseDPrimary\";*/ \n}\n```\n\nTo create a copy of the current theme, you can run:\n\n```bash\nrofi -dump-theme > ~/.config/rofi/current.rasi\n```\n\n## Configuration file format\n\n### Encoding\n\nThe encoding of the file is utf-8. Both Unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But Unix is preferred.\n\n### Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n- Everything between `/*` and `*/` is a comment.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n### White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n### Data types\n\n**ROFI**'s configuration supports several data formats:\n\n#### String\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there\ncan be any printable character.\n\nFor example:\n\n```css\n\n ml-row-down: \"ScrollDown\";\n```\n\n#### Number\n\nAn integer may contain any full number.\n\nFor example:\n\n```css\neh: 2;                        \n```\n\n#### Boolean\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\nshow-icons: true;\n```\n\nThis is equal to the `-show-icons` option on the commandline, and `show-icons:\nfalse;` is equal to `-no-show-icons`.\n\n#### List\n\nThis is not supported by the old configuration system, but can be used in the\n**rasi** format.\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The entry in the list single ASCII words.\n\n```css\n combi-modes: [window,drun];\n```\n\nFor older versions you have :\n\n```css\n combi-modes: \"window,drun\";\n```\n\n## Get a list of all possible options\n\nThere are 2 ways to get a list of all options:\n\n1. Dump the configuration file explained above. (`rofi -dump-config`)\n1. Look at output of `rofi -h`.\n\nTo see what values an option support check the manpage, it describes most of\nthem.\n\nNOTE: not all options might be in the manpage, as options can be added at\nrun-time. (f.e. by plugins).\n\n## Splitting configuration over multiple files\n\nIt is possible to split configuration over multiple files using imports. For\nexample in `~/.config/rofi/config.rasi`\n\n```css\nconfiguration {\n}\n@import \"myConfig\"\n@theme \"MyTheme\"\n\n```\n\nRofi will first parse the config block in `~/.config/rofi/config.rasi`, then\nparse `~/.config/rofi/myConfig.rasi` and then load the theme `myTheme`.  More\ninformation can be obtained from the **rofi-theme(5)** manpage.  Imports can be\nnested.\n"
  },
  {
    "path": "COPYING",
    "content": "MIT/X11 License\nModified  2013-2024 Qball Cow <qball@gmpclient.org>\nCopyright (c) 2012 Sean Pringle <sean.pringle@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Changelog",
    "content": "For newer release ChangeLogs please see the releasenotes.\n\nv1.7.3: Sturtled!\n   - [Help] Print out the parsed config/theme files in -help output.\n   - [Keybindings] Fix keybindings being modified by -theme-str\n   - [Doc] Add rofi-dmenu manpage.\n   - [XCB] Cache lookup of monitor.\n   - Add -replace option (#568)\n   - Fix memory leak.\n   - [1566] Add extra debug for resolving monitors.\n   - [Theme] Add round,floor,ceil function in @calc (#1569)\n   - [Doc] Explain icon lookup.\n   - [Combi] Add -combi-display-format (#1570) (thanks to Jakub)\n   - [Theme] Expand list type ([]) for more data types.\n   - [Theme] Add support for tab-stops on textbox. (#1571) (thanks to Jakub)\n   - [Theme] Testing direct access to widgets via cmdline option (-theme+widget+property value)\n\nv1.7.2: Shellebrations!\n   - [Build] Fix building without window mode enabled.\n   - [Config] Do not print out the 'theme' field in configuration on dump.\n   - [CI] test window mode less build.\n   - Allow configuration block in theme again.\n\nv1.7.1: Turtley amazing!\n   - [Theme] Fix highlight with only theme.\n   - Updated documentation and landing page (Thanks to RaZ0rr-Two)\n   - [Combi] Fix nesting combi modi (#1510)\n   - [DMenu] Fix crash dmenu mode when no entry is available. (#1504)\n   - [Run|Drun] Only initialize file-completer on first use.\n   - [FileBrowser] Reduce number of re-allocs.\n   - [Readme] Remove generating readme.html for dist.\n   - [Dmenu] Fix uninitialized memory (non-selectable)\n   - [FileBrowser] Try to convert invalid encoded text. (#1471)\n   - [FileBrowser] Don't crash on invalid file filenames. (#1471)\n   - [Theme] print known colors as its color name.\n   - [CMD] If failed to convert commandline to new option, do not stop. (#1425)\n   - [Theme] Fix parsing of nested media blocks. (#1442)\n   - [Widgets] Fix sizing logic widgets. (#1437)\n   - [Window] Try to fix auto-sizing of desktop names for non-i3 desktops. (#1439)\n   - [Window] Fix broken close-on-delete. (#1421)\n   - [Listview] Correctly check if selected item is highlighted. (#1423)\n   - [Entry] Allow action to be taken on input change. (#1405)\n   - [Theme] Don't truncate double values. (#1419)\n   - [Grammar] Add support for env(ENV,default).\n   - [Documentation] documentation fixes.\n   - [Theme] fix dmenu theme ( #1396).\n\nv1.7.0: Iggy 2024\n   - ADD: -steal-focus option.\n   - ADD: [Config] Add nested configuration option support.\n   - ADD: [Config] Support for handling dynamic config options.\n   - ADD: [IconFetcher] Find images shipped with the theme.\n   - ADD: [DRun] Add support for passing file (using file-browser) completer for desktop files that support his.\n   - ADD: [DRun] Support for service files.\n   - ADD: [FileBrowser] Allow setting startup directory (#1325)\n   - ADD: [FileBrowser]: Add sorting-method. (#1340)\n   - ADD: [FileBrowser] Add option to group directories ahead of files. (#1352)\n   - ADD: [Filtering] Add prefix matching method. (#1237)\n   - ADD: [Icon] Add option to square the widget.\n   - ADD: [Icon|Button] Make action available on icon, button and keybinding name.\n   - ADD: [KeyBinding] Add Ctrl-Shift-Enter option. (#874)\n   - ADD: [ListView]-hover-select option. (#1234)\n   - ADD: [Run] Add support for passing file (using file-browser) completer.\n   - ADD: [Textbox] Allow theme to force markup on text widget.\n   - ADD: [Theme] theme validation option. (`-rasi-validate`)\n   - ADD: [View] Add support for user timeout and keybinding action.\n   - ADD: [Widget] Add cursor property (#1313)\n   - ADD: [Widget] Add scaling option to background-image.\n   - ADD: [Widget] Add support background-image and lineair gradient option.\n   - ADD: [Window] Add pango markup for window format (#1288)\n   - ADD: [Window] Allow rofi to stay open after closing window.\n   - FIX: [DSL] Move theme reset into grammar parser from lexer.\n   - FIX: [Drun]: fix sorting on broken desktop files. (thanks to nick87720z)\n   - FIX: [File Browser]: Fix escaping of paths.\n   - FIX: [ListView] Fix wrong subwidget name.\n   - FIX: [Script] Don't enable custom keybindings by default.\n   - FIX: [TextBox] Fix height estimation.\n   - FIX: [Theme] widget state and inherited properties. This should help fixing some old themes with changes from 1.6.1.\n   - FIX: [Widget] Fix rendering of border and dashes. (Thanks to nick87720z)\n   - FIX: [Build] Fix CI.\n   - FIX: [Theme] Discard old theme, when explicitly passing one on command line.\n   - REMOVE: -dump-xresources\n   - REMOVE: -fullscreen\n   - REMOVE: -show-match\n   - REMOVE: Old xresources based configuration file.\n   - REMOVE: fake transparency/background option, part of theme now.\n   - REMOVE: xresources parsing via Xserver\n   - Remove: [Theme] Remove backwards compatiblity hack.\n   - DOC: Update changes to manpages\n\n\nv1.6.1: Tortoise Power\n   - Use GdkPixbuf for Icon parsing.\n   - Add FileBrowser to default mode.\n   - Fix parsing dicts in config file (with \" in middle of string.)\n   - Add -normalize-match option, that tries to o match ö, é match e. (#1119)\n   - [Theme] Add min/max operator support to calc() (#1172)\n   - Show error message and return to list instead of closing (#1187)\n   - [Theme] Add nested media support. (#1189)\n   - [Textbox] Try to fix estimated font height. (#1190)\n   - [DRun] Fix broken caching mechanism.\n\nv1.6.0: The Masked Launcher\n   -  Add `themes/` directory in the users rofi config directory to the theme search path. (#1001)\n   -  Split listview element into box widget holding icon and textbox. Supporting more dynamic themes. (#949)\n   -  Fix default theme.\n   -  Add -upgrade-config option.\n   -  Add `ROFI_PLUGIN_PATH` variable.\n   -  Add check for running rofi inside a Script mode.\n   -  Remove gnome-terminal from rofi-sensible-terminal (#1074)\n   -  Set window title based on mode name. (#969)\n   -  Subpixel rendering workaround. (#303)\n   -  Support character type in configuration {} block . (#1131)\n   -  Use `XDG_CONFIG_DIRS` (#1133)\n   -  [Box] Bug fix update propagation.\n   -  [Build] Fix meson build with meson 0.55.\n   -  [DMenu] Add `-keep-right` flag. (#1089)\n   -  [DMenu] Don't match markup when filtering. (#579,#1128)\n   -  [DRUN] Support Type=Link (#1166)\n   -  [DRun] Add % to escape variable.\n   -  [DRun] Add an optional cache for desktop files. (#1040)\n   -  [DRun] Add keywords as default match item. (#1061)\n   -  [DRun] Don't run custom commands.\n   -  [DRun] Match keywords field.\n   -  [DRun] Only show selected categories. (#817)\n   -  [Dmenu|Script] Add non-selectable entries. (#1024)\n   -  [Doc] Update documentation.\n   -  [IconFetcher] Add jpeg support.\n   -  [Icon] Set default size to 1.2 CH.\n   -  [Icon] support distance for size.\n   -  [Listview] Add widget to show keybinding index. (#1050)\n   -  [Listview] Fix distribution of remaining space.\n   -  [Listview] Fix left-to-right scrolling. (#1028)\n   -  [Listview] Fix updating elements. (#1032)\n   -  [Matching] Make Fuzzy matching non greedy.\n   -  [Script] Add delimiter option. (#1041)\n   -  [Script] Add environment variable indicating state.\n   -  [Script] Add extra matchign field (meta). (#1052)\n   -  [Script] Add info option, hidden field that gets passed to script via `ROFI_INFO` environment.\n   -  [Script] Add no-custom option.\n   -  [Textbox] Add cursor blinking option.\n   -  [Textbox] Add placeholder. (#1020)\n   -  [Theme] Add `calc()` support. (#1105)\n   -  [Theme] Add alpha channel to highlight color. (#1033)\n   -  [Theme] Add sidebar as mode-switcher alias.\n   -  [Theme] Add some initial @media support. (#893)\n   -  [Theme] Support buttons in the UI.\n   -  [View] Add two widgets. One showing number of rows, other number of filtered rows. (#1026)\n   -  [Window] Add window thumbnail option.\n   -  [Window] Remove arbitrary # window limit. (#1047)\n   -  [Window] check buffer overflow.\n\nv1.5.5:\nv1.5.4: Painful tardiness\n\t- SSH: Fix wrong malloc size, causing crash.\n\nv1.5.3: Time delayed progress\n\t- Update manpage with missing entry. (#937)\n\t- Rename sidebar widget to mode-switcher and allow configuration from theme.\n\t- Timing: Moving timing output to glib debug system.\n\t- SSH: Fix unitialized variable issue.\n\t- SSH: resolve ':' conflict in history entries.\n\t- RASI Lexer: Fix nested () in variable default field.\n\t- USABILITY: When mode not found, show in gui not just on commandline.\n\t- ICON: Allow aligning image in icon widget.\n\t- Meson build system: cleanups and improvements.\n\t- Meson build system: add documentation (#943)\n\t- Window: Fix default formatting and remove (invalid) deprecation warning.\n\t- DMenu: Add support for showing icons infront of displayed list.\n\t- Overlay: Fix overlay widget to correctly integrate in new theme format.\n\t- Update libnkutils, libgwater.\n\t- SSH: be case-insensitive when parsing keywords.\n\t- DMENU: Add format option to strip pango markup from return value.\n\t- ListView: allow user to change ellipsizing displayed value at run-time.\n\nv1.5.2: Procrastination in progress\n\t- Clearify Check dependency. (#879)\n\t- Add option to change negate character. (#877)\n\t- Fix assert and update test. (#875)\n\t- Add missing example Script (#869)\n\t- Add drun-display-format option. (#858)\n\t- Fixing typos (#867,#837,#831,#804)\n\t- Fix loading icons that are in cache (#860)\n\t- Improve ssh known_host parser. (#820)\n\t- Add terminals to rofi-sensible-terminal (#808)\n\t- Lexer Fix several ambiguity and handling of empty input.\n\t- IconFetcher preload the user set icon theme.\n\t- IconFetcher use generic threadpool.\n\t- Lexer support environment variables.\n\t- Cleanup syntax for sorting. (#816)\n\t- Documents update.\n\t- Fix how borders are drawn. (#792, #783)\n\nv1.5.1:\n\t- Egor Zvorykin: Fix typos in theme manpage. (#760)\n\t- Ben: Fix README config file location. (#761)\n\t- [SSH] Reload when ssh entry is deleted.\n\t- Add support for randr 1.5 monitors. (#749)\n\t- Diki Anata: Fix border layout structure.\n\t- Remove duplicate tests. (#543)\n\t- Fix make test in libnkutils.\n\nv1.5.0:\n\t- [Theme] Accept integer notation for double properties. (#752)\n\t- [View] Theme textboxes are vertically sized and horizontal wrapped. (#754)\n\t- Rofi 1.4.2 doesn't capture ←, ↑, →, ↓ binding to keys to work in combination with Mode_switch (#744)\n\t- Add konsole to list of sensible terminals. (#739)\n\t- Allow drun to filter based on comment field. (#733)\n\t- Add prompt widget to default theme.\n\t- Add manpage for rofi-theme-selector.\n\t- Dump theme without # prefix and separator .\n\t- Fix issue with xnomad and -4 placing. (#683)\n\t- DRun obey OnlyShowIn and NotShowIn properties.\n\t- Store default theme in rofi binary using GResources.\n\t- Add extra margin between prompt and entry.\n\t- Remove colon from prompt. (#637)\n\t- Add support for passing extra properties in script mode.\n\t- Better error message on invalid argb syntax.\n\t- Fix default theme border.\n\t- Make '#' in the parser optional.\n\t- Update themes.\n\t- Add -drun/window-match-fields option (thx to Askrenteam) for drun/window menu. (#690/#656)\n\t- Implement negated match. (#665)\n\t- Fix parsing of non-existing fields. (#700)\n\t- rofi-theme-selector fixes.\n\t- Fix spelling error (thx to jmkjaer)\n\t- Fix test on i686/arm. (#692)\n\t- Fix error in theme manpage. (#686)\n\t- Allow history size to be specified. (#613)\n\t- Fix drun history implementation. (#579)\n\t- Add gentoo install instruction. (#685)\n\nv1.4.2:\n\t- Add sort to manpage. (#682)\n\t- Add tranaparent to theme manpage. (#688)\n\t- Re-add theme headers. (#679)\n\t- Fix super key. (#684)\n\t- Unknown option libnkutils:uuid. (#677)\n\t- Mode window is not found. (#686)\n\t- Fix meson build in dist file.\n\nv1.4.1: All Hail Rasi\n\t- Bump meson release version\n\nv1.4.0: I reject your truth and substitute my own\n\tNew Features:\n\t\t- FZF style sorting for fuzzy matching (thanks to MaskRay) (#533)\n\t\t- Improve error messages.\n\t\t  - Theme parsing.\n\t\t  - Keybinding.\n\t\t  - invalid commandline options.\n\t\t  - etc.\n\t\t- Customizable highlight.\n\t\t- Give up when keyboard is not grabbed in first 5 seconds.\n\t\t- Improved manpage\n\t\t\t- rofi (1)\n\t\t\t- rofi-themes (5)\n\t\t- Super-{1..10} hotkey for first 10 rows.\n\t\t- Allow x-align/y-align for textbox.\n\t\t- Support matching bangs on multiple characters in combi mode. (#542)\n\t\t- Set WM_CLASS (#549)\n\t\t- Async pre-read 25 rows for improving user experience. (#550)\n\t\t- Improve handling in floating window manager by always setting window size.\n\t\t- DRun speedup.\n\t\t- Make lazy-grab defualt.\n\t\t- Remove extra layer in textbox. (#553)\n\t\t- Ignore fonts that result in a family name or size 0. (#554)\n\t\t- [Combi] Allow bang to match multiple modes. (#552)\n\t\t- Add detection of window manager and work around quirks.\n\t\t- Support dynamic plugins.\n\t\t- DMENU tty detection.\n\t\t- Support for icons in drun, combi and window mode.\n\t\t- Startup notification of launched application support.\n\t\t- Meson support.\n\t\t- Fuzzy matching with fzf based sorting algorithm.\n\t\t- Auto-detect DPI.\n\t\t- Set cursor at the end of the input field. (#662)\n\t\t- Meson support (thx to SardemFF7).\n\t\t- [Script] parse the command as if it was commandline. (#650)\n\t\t- Don't enable asan by meson. (#642)\n\t\t- Allow text widgets to be added in theme and string to be set.\n\t\t- [Dmenu] Support the -w flag.\n\t\t- Allow window (via window id) to be location for rofi window.\n\t\t- [Dmenu] Allow multi-select mode in `-no-custom` mode.\n\nv1.3.1: Dan vs. Greg: The never ending story, reloaded.\n\tNew Features\n\t\t- [DRun] Search categories. (#449)\n\tImprovements\n\t\t- Fix exit when failed to grab keyboard. (#524)\n\t\t- Introduce lazy keyboard grab mode for people who want rofi to show on key-down in i3.\n\t\t- Add copyrights to theme (needed for debian packaging).\n\t\t- DMENU: Correctly detect end-of-file (#518)\n\t\t- Directly queue redraw on overlay change.\n\t\t- Remove pango markup from workspace names in I3. (#507)\n\nv1.3.0: Dan vs. Greg: The never ending story.\n\tNew Features\n\t\t- Use randr for getting monitor layout. Fallback to xinerama if not available.\n\t\t- Re-add fuzzy matcher.\n\t\t- Restructure internal code to use dynamic sizing widgets. (hbox, vbox and lists)\n\t\t- Async mode for dmenu.\n\t\t- Add theme selector script.\n\t\t- Include 21 themes.\n\t\t- Dynamically sizing window with content.\n\t\t- When placed at bottom of screen re-order screen to have entry at bottom.\n\tImprovements\n\t\t- Fix pasting secondary clipboard. (#516)\n\t\t- By default use all cores to filter entries.\n\t\t- Make sure drawing priority is higher then reading input data.\n\t\t- Improve resizing of window, don't make X whipe background.\n\t\t- Improve close window (shift-delete) action, by sending NET_WM_CLOSE instead of destroying window.\n\t\t- Create cache and run directory on startup. (#497)\n\t\t- Fix uneeded redraws on cursor blinking. (#491)\n\t\t- Improve time till grabbing keyboard. (#494)\n\t\t- Better error message when failing to parse keybindings, also continue parsing on error.\n\t\t- Fix problem with custom layouts (#485)\n\t\t- Speedup drawing of screen. Works well now for 4k and 8k screens. (factor 1000+ speedup for the flipping of\n\t\tbuffer) (#496)\n\t\t- DRun mode more compatible with specification.\n\t\t- Debug output via g_log.\n\t\t- Fix password entry cursor position.\n\t\t- Use bash instead of sh for get_git_rev.sh (#445)\n\t\t- Add Control+G for cancel (#452)\n\t\t- Add padding option to textbox (#449)\n\t\t- Ctrl-click does alternate accept entry. (#429)\n\t\t- Hide window decoration in normal window mode.\n\t\t- Click to exit option. (#460)\n\t\t- Fix cursor blinking on moving. (#462)\n\t\t- Remove entry from history if fails to execute (#466)\n\t\t- Fix margins. (#467)\n\t\t- Improved documentation of functions in code.\n\t\t- DRun: Set work directory when executing file. (#482)\n\t\t- Memory leak fixes.\n\t\t- Improve scrollbar behaviour.\n\tRemovals\n\t\t- opacity option. The transparency support in the theme can do the same and more.\n\nv1.2.0\n\tNew Features\n\t\t- Highlight matched part of the string.\n\t\t- Make window switcher string customizable.\n\tImprovements\n\t\t- Improved selection mode in dmenu with selection counter.\n\t\t- Improved selection mode with 'dot' indicator.\n\t\t- Fix Current Desktop window switcher.\n\t\t- Fix launching in terminal.\n\t\t- Supports include in config.\n\t\t- Add Control+k remove till eol keybinding.\n\t\t- Change clear line to Control+w and make Control+u remove till sol (matching readline)\n\t\t- Track origin of option value e.g. who set the option.\n\t\t- Comment default values in dump-xresources.\n\t\t- Fix displaying on 30bit 10bpc X setup.\n\tRemovals:\n\t\t- Remove xlib dependency (xcb-xrm)\n\t\t- Remove fuzzy option\n\t\t- Remove i3 workaround as it no longer needed since I3 v4.9. (Feb. 2015)\n\nv1.1.0\n    New Features\n        - Keys mode, showing keybindings.\n        - Stop cycling option (#407) (Thx to Yaroslav)\n        - Kill window on delete entry (#316)\n    Improvements\n        - Add Control+Backspace as remove word back keybinding.\n        - Allow user to use X11 background for fake transparency (#390)\n        - Allow user to specify background image.\n        - Improved keybinding handling, allowing on-release and modifier only (#384).\n        - Use display name for prompt (#409)\n        - Parse subdirectories in drun parser (#416)\n        - Switch to stop cycling (#407)\n    Bug fixes\n        - Grab mouse pointer with keyboard\n\n1.0.1\n    Bug fixes\n         - Fix typo in manpage.\n         - Return old behaviour for rofi placement (#395, #389)\n         - Switch desktop when switching window (#393)\n         - Remove unneeded use of bash (#391)\n         - Make history parser more robust against corrupted files. (#388)\n         - Fix desktop number (#386)\n\n1.0.0\n    New Features\n\n        - Blinking cursor\n        - BliSeparate configuration file\n        - BliHistory in drun mode (#343)\n        - BliContext menu mode, show rofi at the mouse pointer\n\n    Improvement\n        - auto select and single item on dmenu mode (#281)\n        - Unlimited window title length.\n        - Correctly follow the active desktop, instead of active window.\n        - If requesting modi that is not enabled, show it anyway.\n        - DMenu password mode. (#315)\n        - Levenshtein sort is now UTF-8 aware.\n        - Use xcb instead of large xlib library.\n        - Use GLib mainloop for cleaner code and easier external event based\n        - handling in future.\n        - Run dialog: Try to convert between locale, fs encoding and utf8.\n        - Fixing problems with non-utf8 filesystem encodings.\n        - Try to display non-utf8 strings as good as possible.\n        - Autocomplete bang hint in combi mode (#380)\n        - Remove magic line length limits by switching to getline\n        - from fgets.\n        - Print git version for git builds in version string.\n\n    Bug fixes\n        - Fix subpixel rendering. (#303)\n        - Fix basic tests on OpenBSD (#272)\n        - Fix wrong use of memcpy (thx to Jasperia).\n        - Work around for sigwaitinfo on OpenBSD.\n        - Ignore invalid entries (non-utf8) in dmenu mode.\n        - Glib signal handling.\n        - Fix connecting to i3 on bsd.\n        - Be able to distinguish between empty and cancel in dmenu mode. (#323)\n        - Fix memcpy on single memory region. (#312)\n        - Fix opening file with mode a+ and using fseek to overwrite on bsd.\n\n0.15.12:\n    New features:\n        - Initial `-dump` command for dmenu mode. (#216)\n        - Threading support.\n            - Parallel checking for ASCII.\n            - Parallel string matching.\n            - Autodetect number of HW-threads.\n            - Disabled by default.\n        - Highlight multiple selected rows (#287,#293)\n        - Dmenu can read from file instead of stdin.\n        - Regex matching (#113)\n        - Take Screenshot of rofi using keybinding.\n        - Hotkey for sorting: (#298)\n\t\t- Option to set scrollbar width.\n    Improvements:\n\t\t- Fix return code of multi-select.\n        - Update manpage (#289, #291)\n        - Improve speed of reading stdin in dmenu mode.\n        - Correctly handle modifier keys now. Should now support most weird keyboard layouts and switching between them.\n        (#268, #265, #286)\n        - Correctly set locale, fixing issues with entering special characters. (#282)\n        - DRun mode support `NoDisplay` setting (#283)\n        - Pango markup is matched when filtering. (#273)\n    Bug fixes:\n        - Improve error message (#290)\n        - Correctly switch to next entry on multi-select when list is filtered (#292)\n        - Switch __FUNCTION__ for __func__. (#288)\n        - Fix segfault on empty list and moving through it. (#256,#275)\n        - Fix one off of colors (#269)\n        - Drun fix uninitialized memory (#285)\n\n0.15.11:\n    New features:\n        - (Experimental) Desktop file support\n    Improvement:\n        - Add xdg-terminal to rofi-sensible-terminal\n    Bug fixes:\n        - manpage fixes (#261)\n        - Crash in error mesg on invalid config\n        - Fix urgent and active being activated at same time\n        - Fix crasher on empty list\n0.15.10:\n    New feature:\n        - Support for Startup Notification\n        - Standalone mode in dmenu\n        - ssh: known_hosts parsing\n        - Full screen support\n        - Glob style matching\n        - Cairo drawing\n        - Fast ascii filtering (thx to Tom Hinton)\n        - Combi bang support\n        - normal window mode for dmenu\n        - Startup notification support\n        - Current desktop window mode\n    Improvements:\n        - Keep same line selected\n        - Cleanup menu code by re-using Switcher\n        - Fix drawing on resize\n        - Fix rofi -h output\n        - allow disabling of tokenizing\n        - Dragging scrollbar\n        - Allow none type on separator\n        - Dmenu support markup in fields\n    Bug fixes:\n        - dmenu use switcher system\n        - release keyboard on focus out event, regrab it on focus in event\n        - Support `\\0` separator\n\n0.15.8:\n    New feature:\n        - Scrollbar.\n        - More custom keybindings.\n    Improvements:\n        - dmenu compatibility.\n        - Don't refilter on all keypresses.\n        - Hide Docks and desktops from the window list. (remove i3bar hack)\n    Bug fixes:\n        - Fix Desktop numbering.\n        - Mis-alignment of arrow down box with message (#189)\n        - Fix issue with mouse interaction needing keyboard press to complete.\n        - Fix -no-custom still allows escape to quit.\n        - Fix compiler warnings.\n        - Fix dmenu mode. (#200)\n        - Break CMD AI to have dmenu compatibility.\n        - Fix processing of signals.\n\n0.15.7:\n    Bug fixes:\n        - Auto-wrap text in message dialog.\n        - Fix ellipsiziing in entry box.\n        - Fix crash on empty list with custom input (#175).\n        - SSH: Ignore comments in Host line (#178).\n        - Fix issues with BSD (#180)\n    New feature:\n        - Markup support error message.\n        - Implement -no-custom as alternative to -only-select (#176).\n        - Fuzzy match option. (#133)\n    Improvements:\n        - Make more keys user-configurable. (#66)\n\n0.15.5:\n    Bug fixes:\n        - Reduce time waiting for keyboard grab (#153)\n        - Also grab Key Release on exit. (#167)\n        - Fix failing font size estimation code.\n    New feature:\n        - [DMENU] Allow to select line matching pattern from cmdline.(#165)\n        - [DMENU] Allow to set filter from cmdline. (#164)\n        - [DMENU] Allow output to be formatted (string, filter, index, index 1 based)\n        - [DMENU] Only match input lines mode.\n        - [DMENU] Custom keybinding for return value.(#154,#156)\n        - [DMENU] Allow additional message line. (#166)\n    Improvements:\n        - (Start) adding keybinding support (#131)\n        - Cleanup warnings from clang checkers.\n        - Fix keybindings on Russian layout (#169)\n    Open bugs:\n        - Urgency hint not always working (#162)\n\n0.15.4:\n    New feature:\n        - Number mode for dmenu. allows user to get index back instead of content.\n        - Combi mode. Combine multiple views into one.\n        - Highlight current window.\n        - Highlight urgent and active row in window view.\n        - DMenu allow rows to be highlighted. (single, multiple, ranges)\n        - New color specification based on I3. (Can be enabled by settings) (#147)\n        - /etc/hosts support for ssh mode. (#137)\n    Bug fixes:\n        - On a single item in list disable auto-select.\n        - Fix cursor position (#140)\n        - Resolving manpage. (#142)\n        - Fix pasting cursor one off. (#150)\n        - Fix grave key -> ctrl+grave (#151)\n    Improvements:\n        - Better handle input methods.. Now international keyboard layout works as expected: `e ->è\n        - Be more verbose about starting in daemon mode.\n        - Print a user-understandable error when launching in daemon mode without a key bound.\n        - Add Ctrl(Shift)Tab to switch modi's.\n        - Auto size number of columns based on available columns.\n        - Better way to determine font height.\n        - Fix font vertical centering.\n        - One-off when pasting text.\n        - Improve rendering of boxes (fixed height and margins)\n        - Fix modi switcher boxes size+layout.\n        - Reduce work on redraws (do not always calculate new size/position), set text, etc.\n        - OO-ify the switchers.\n        - Remove unneeded filtered array.\n    Cleanup:\n        - Do not lug argc,argv around everywhere.\n\n0.15.2:\n    Removed features:\n        - Remove (broken) hmode\n        - Old style key binding and mode launcher.\n        - Old TIMING code.\n    New features:\n        - Word movement in entry box. (#126)\n        - PID file to avoid duplicate Rofi.\n        - Generic keybinding and launching for modi. (#128)\n        - Auto select mode (previously called zeltak mode)\n    Bug fixes:\n        - Shift left/right movement between modi (#125)\n        - Document updates (#123,#116,#124,etc.)\n        - DMenu mode based on executable name with full path (#119)\n        - Fix missing keystrokes.\n        - On broken UTF-8 show everything up to the broken character. (#121)\n    Others:\n        - Significant code refactoring.\n        - Rewriting of config parser, Commandline Parser uses structure from Xresource parser.\n          Avoiding duplication and making it easier to maintain.\n    Performance improvements:\n        - Fix blocking on grabbing keyboard.\n\n0.15.1:\n    New features:\n        - Improved transparency\n        - Changelog\n        - Case sensitivity support, with indicator. (Edwin Pujols)\n        - Mouse scroll wheel support\n        - Alternate Row colors\n        - Run-list command for adding entries to run-dialog\n        - Dmenu: preselect line.\n    Bug fixes:\n        - Manpage fixes\n        - SSH viewer, support lists of hostnames (Tblue)\n        - SSH improve parsing of odly indented host files\n        - Do not loose keypresses when system under load\n        - Cleanups, small fixes. (Edwin Pujols, blueyed )\n    Performance improvements:\n        - Lazy refilter for large lists\n"
  },
  {
    "path": "Examples/i3_empty_workspace.sh",
    "content": "#!/usr/bin/env bash\n\nMAX_DESKTOPS=20\n\nWORKSPACES=$(seq -s '\\n' 1 1 \"${MAX_DESKTOPS}\")\n\nEMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\\n' | grep num | awk -F: '{print int($2)}' ; \\\n            echo -e \"${WORKSPACES}\" ) | sort -n | uniq -u | head -n 1)\n\ni3-msg workspace \"${EMPTY_WORKSPACE}\"\n"
  },
  {
    "path": "Examples/i3_switch_workspaces.sh",
    "content": "#!/usr/bin/env bash\n\nif [ -z $@ ]\nthen\ngen_workspaces()\n{\n    i3-msg -t get_workspaces | tr ',' '\\n' | grep \"name\" | sed 's/\"name\":\"\\(.*\\)\"/\\1/g' | sort -n\n}\n\necho empty; gen_workspaces\nelse\n    WORKSPACE=$@\n\n    if [ \"${WORKSPACE}\" = \"empty\" ]\n    then\n        i3_empty_workspace.sh >/dev/null\n    elif [ -n \"${WORKSPACE}\" ]\n    then\n        i3-msg workspace \"${WORKSPACE}\" >/dev/null\n    fi\nfi\n"
  },
  {
    "path": "Examples/rofi-file-browser.sh",
    "content": "#!/usr/bin/env bash\n\n# Various options for the file browser script:\nROFI_FB_GENERIC_FO=\"xdg-open\" # command used for opening the selection\nROFI_FB_PREV_LOC_FILE=~/.local/share/rofi/rofi_fb_prevloc\nROFI_FB_HISTORY_FILE=~/.local/share/rofi/rofi_fb_history\nROFI_FB_HISTORY_MAXCOUNT=5 # maximum number of history entries\n# Comment the next variable to always start in the last visited directory,\n# otherwise rofi_fb will start in the specified directory:\nROFI_FB_START_DIR=$HOME # starting directory\n# Uncomment the following line to disable history:\n# ROFI_FB_NO_HISTORY=1\n\n# Beginning of the script:\n# Create the directory for the files of the script\nif [ ! -d \"$(dirname \"${ROFI_FB_PREV_LOC_FILE}\")\" ]\nthen\n    mkdir -p \"$(dirname \"${ROFI_FB_PREV_LOC_FILE}\")\"\nfi\nif [ ! -d \"$(dirname \"${ROFI_FB_HISTORY_FILE}\")\" ]\nthen\n    mkdir -p \"$(dirname \"${ROFI_FB_HISTORY_FILE}\")\"\nfi\n\n# Initialize $ROFI_FB_CUR_DIR\nif [ -d \"${ROFI_FB_START_DIR}\" ]\nthen\n    ROFI_FB_CUR_DIR=\"${ROFI_FB_START_DIR}\"\nelse\n    ROFI_FB_CUR_DIR=\"$PWD\"\nfi\n\n# Read last location, otherwise we default to $ROFI_FB_START_DIR or $PWD.\nif [ -f \"${ROFI_FB_PREV_LOC_FILE}\" ]\nthen\n    ROFI_FB_CUR_DIR=$(cat \"${ROFI_FB_PREV_LOC_FILE}\")\nfi\n\n# Handle argument.\nif [ -n \"$@\" ]\nthen\n    if [[ \"$@\" == /* ]]\n    then\n        ROFI_FB_CUR_DIR=\"$@\"\n    else\n        ROFI_FB_CUR_DIR=\"${ROFI_FB_CUR_DIR}/$@\"\n    fi\nfi\n\n# If argument is no directory.\nif [ ! -d \"${ROFI_FB_CUR_DIR}\" ]\nthen\n    if [ -x \"${ROFI_FB_CUR_DIR}\" ]\n    then\n        coproc ( \"${ROFI_FB_CUR_DIR}\" >/dev/null 2>&1 )\n        exec 1>&-\n        exit;\n    elif [ -f \"${ROFI_FB_CUR_DIR}\" ]\n    then\n        if [[ \"${ROFI_FB_NO_HISTORY}\" -ne 1 ]]\n        then\n            # Append selected entry to history and remove exceeding entries\n            sed -i \"s|${ROFI_FB_CUR_DIR}|##deleted##|g\" \"${ROFI_FB_HISTORY_FILE}\"\n            sed -i '/##deleted##/d' \"${ROFI_FB_HISTORY_FILE}\"\n            echo \"${ROFI_FB_CUR_DIR}\" >> \"${ROFI_FB_HISTORY_FILE}\"\n            if [ \"$( wc -l < \"${ROFI_FB_HISTORY_FILE}\" )\" -gt \"${ROFI_FB_HISTORY_MAXCOUNT}\" ]\n            then\n                sed -i 1d \"${ROFI_FB_HISTORY_FILE}\"\n            fi\n        fi\n        # Open the selected entry with $ROFI_FB_GENERIC_FO\n        coproc ( \"${ROFI_FB_GENERIC_FO}\" \"${ROFI_FB_CUR_DIR}\" >/dev/null 2>&1 )\n        if [ -d \"${ROFI_FB_START_DIR}\" ]\n        then\n            echo \"${ROFI_FB_START_DIR}\" > \"${ROFI_FB_PREV_LOC_FILE}\"\n        fi\n        exit;\n    fi\n    exit;\nfi\n\n# Process current dir.\nif [ -n \"${ROFI_FB_CUR_DIR}\" ]\nthen\n    ROFI_FB_CUR_DIR=$(readlink -e \"${ROFI_FB_CUR_DIR}\")\n    echo \"${ROFI_FB_CUR_DIR}\" > \"${ROFI_FB_PREV_LOC_FILE}\"\n    pushd \"${ROFI_FB_CUR_DIR}\" >/dev/null\nfi\n\n# Output to rofi\nif [[ \"${ROFI_FB_NO_HISTORY}\" -ne 1 ]]\nthen\n    tac \"${ROFI_FB_HISTORY_FILE}\" | grep \"${ROFI_FB_CUR_DIR}\"\nfi\necho \"..\"\nls\n# vim:sw=4:ts=4:et:\n"
  },
  {
    "path": "Examples/test_script_env.sh",
    "content": "#!/usr/bin/env bash\n\nif [ -z \"${ROFI_OUTSIDE}\" ]\nthen\n    echo \"run this script in rofi\".\n    exit\nfi\n\necho -en \"\\x00no-custom\\x1ffalse\\n\"\necho -en \"\\x00data\\x1fmonkey do, monkey did\\n\"\necho -en \"\\x00use-hot-keys\\x1ftrue\\n\"\necho -en \"${ROFI_RETV}\\x00icon\\x1ffirefox\\x1finfo\\x1ftest\\n\"\n\nif [ -n \"${ROFI_INFO}\" ]\nthen\n    echo \"my info: ${ROFI_INFO} \"\nfi\nif [ -n \"${ROFI_DATA}\" ]\nthen\n    echo \"my data: ${ROFI_DATA} \"\nfi\n"
  },
  {
    "path": "Examples/test_script_mode.sh",
    "content": "#!/usr/bin/env bash\n\nif [ \"$*\" = \"quit\" ]; then\n\texit 0\nfi\n\nif [ \"$@\" ]; then\n\t# Override the previously set prompt.\n\techo -en \"\\x00prompt\\x1fChange prompt\\n\"\n\tfor a in {1..10}; do\n\t\techo \"$a\"\n\tdone\n\techo \"quit\"\nelse\n\techo -en \"\\x00prompt\\x1ftesting\\n\"\n\techo -en \"\\0urgent\\x1f0,2\\n\"\n\techo -en \"\\0active\\x1f1\\n\"\n\techo -en \"\\0markup-rows\\x1ftrue\\n\"\n\techo -en \"\\0message\\x1fSpecial <b>bold</b>message\\n\"\n\n\techo -en \"aap\\0icon\\x1ffolder\\n\"\n\techo -en \"blob\\0icon\\x1ffolder\\x1fdisplay\\x1fblub\\n\"\n\techo \"noot\"\n\techo \"mies\"\n\techo -en \"-------------\\0nonselectable\\x1ftrue\\x1fpermanent\\x1ftrue\\n\"\n\techo \"testing\"\n\techo \"<b>Bold</b>\"\n\techo \"quit\"\nfi\n"
  },
  {
    "path": "Examples/test_script_mode_color.sh",
    "content": "#!/usr/bin/env bash\n\nif [ \"$*\" = \"quit\" ]\nthen\n    exit 0\nfi\n\nif [ \"$@\" ]\nthen\n    # Override the previously set prompt.\n    echo -en \"\\0theme\\x1felement-text { background-color: $@;}\\n\"\n    echo -en \"\\0keep-selection\\x1ftrue\\n\"\n#    echo -en \"\\0new-selection\\x1f2\\n\"\n    echo \"red\"\n    echo \"lightgreen\"\n    echo \"lightblue\"\n    echo \"lightyellow\"\n    echo \"quit\"\nelse\n    echo -en \"\\x00prompt\\x1ftesting\\n\"\n    echo -en \"\\0urgent\\x1f0,2\\n\"\n    echo -en \"\\0active\\x1f1\\n\"\n    echo -en \"\\0keep-selection\\x1ftrue\\n\"\n    echo -en \"\\0message\\x1fSpecial <b>bold</b>message\\n\"\n\n    echo \"red\"\n    echo \"lightgreen\"\n    echo \"lightblue\"\n    echo \"lightyellow\"\n    echo \"pink\"\n    echo \"green\"\n    echo \"blue\"\n    echo \"gold\"\n    echo \"quit\"\nfi\n"
  },
  {
    "path": "Examples/test_script_mode_delim.sh",
    "content": "#!/usr/bin/env bash\n\nif [[ \"$@\" = \"quit\" ]]\nthen\n    exit 0\nfi\n\n# Override the previously set prompt.\n# We only want to do this on first call of script.\nif [[ $ROFI_RETV = 0 ]]\nthen\n    echo -en \"\\x00delim\\x1f\\\\x1\\n\"\nfi\necho -en \"\\x00message\\x1fmy line1\\nmyline2\\nmy line3\\x1\"\necho -en \"\\x00prompt\\x1fChange prompt\\x1\"\nfor a in {1..10}\ndo\n    echo -en \"$a\\x1\"\ndone\necho -en \"newline\\ntest\\x1\"\necho -en \"quit\"\n"
  },
  {
    "path": "INSTALL.md",
    "content": "# Installation guide\n\nThis guide explains how to install rofi using its build system and how you can\nmake debug builds.\n\nRofi uses [Meson](https://mesonbuild.com/) as build system.\nBe default rofi builds with both backends (x11 and wayland) if available on the\nsystem. If no backend is found, it will give an error.\nYou can force the build system to disable the [wayland](#disable-wayland-support)\nor [x11](#disable-x11-support) backend.\n\n## DEPENDENCY\n\n### For building\n\n- C compiler that supports the c99 standard. (gcc or clang)\n\n- meson\n\n- ninja\n\n- pkg-config\n\n- flex 2.5.39 or higher\n\n- bison\n\n- check (Can be disabled using the `--disable-check` configure flag)\n    check is used for build-time tests and does not affect functionality.\n\n- Developer packages of the external libraries\n\n- glib-compile-resources\n\n### External libraries\n\n- libpango >= 1.50\n\n- libpangocairo\n\n- libcairo\n\n- libcairo-xcb\n\n- libglib2.0 >= 2.72\n  - gmodule-2.0\n  - gio-unix-2.0\n\n- libgdk-pixbuf-2.0\n\n- libstartup-notification-1.0\n\n- libxkbcommon >= 0.4.1\n\n- libxkbcommon-x11\n\n- libxcb (sometimes split, you need libxcb, libxcb-xkb and libxcb-randr\n    libxcb-xinerama)\n\n- xcb-util\n\n- xcb-util-wm (sometimes split as libxcb-ewmh and libxcb-icccm)\n\n- xcb-util-cursor\n\n- xcb-imdkit  (optional, 1.0.3 or up preferred)\n\nOn debian based systems, the developer packages are in the form of:\n`<package>-dev` on rpm based `<package>-devel`.\n\nFor wayland support:\n\n- wayland\n- wayland-protocols >= 1.17\n\n## Install from a release\n\nWhen downloading from the github release page, make sure to grab the archive\n`rofi-{version}.tar.[g|x]z`. The auto-attached files `source code (zip|tar.gz)`\nby github do not contain a valid release. It misses a setup build system and\nincludes irrelevant files.\n\n### Meson\n\nCheck dependencies and configure build system:\n\n```bash\n    meson setup build\n```\n\nBuild Rofi:\n\n```bash\n    ninja -C build\n```\n\nThe actual install, execute as root (if needed):\n\n```bash\n    ninja -C build install\n```\n\nThe default installation prefix is: `/usr/local/` use `meson setup build\n--prefix={prefix}` to install into another location.\n\n## Install a checkout from git\n\nThe GitHub Pages version of these directions may be out of date.  Please use\n[INSTALL.md from the online repo][master-install] or your local repository.\n\nIf you don't have a checkout:\n\n```bash\n    git clone --recursive https://github.com/DaveDavenport/rofi\n    cd rofi/\n```\n\nIf you already have a checkout:\n\n```bash\n    cd rofi/\n    git pull\n    git submodule update --init\n```\n\nFrom this point, use the same steps you use for a release.\n\n## Options for building\n\nWhen you run the configure step there are several options you can configure.\n\nFor Meson, before the initial setup, you can see rofi options in\n`meson_options.txt` and Meson options with `meson setup --help`. Meson's\nbuilt-in options can be set using regular command line arguments, like so:\n`meson setup build --option=value`. Rofi-specific options can be set using the\n`-D` argument, like so: `meson setup build -Doption=value`. After the build dir\nis set up by `meson setup build`, the `meson configure build` command can be\nused to configure options, by the same means.\n\nThe most useful one to set is the installation prefix:\n\n```bash\n    # Meson\n    meson setup build --prefix <installation path>\n```\n\nf.e.\n\n```bash\n    # Meson\n    meson setup build --prefix /usr\n```\n\n### Disable x11 support\n\n```bash\nmeson setup build -Dxcb=disabled\n```\n\n### Disable wayland support\n\n```bash\nmeson setup build -Dwayland=disabled\n```\n\n### Install locally\n\nor to install locally:\n\n```bash\n    # Meson\n    meson setup build --prefix ${HOME}/.local\n```\n\n### Verbose build output\n\nShow the commands called (when using ninja):\n\n```bash\n    # Meson\n    ninja -C build -v\n```\n\n### Debug build\n\nCompile with debug symbols and no optimization, this is useful for making\nbacktraces:\n\n```bash\n    # Meson\n    meson configure build --debug\n    ninja -C build\n```\n\n### Get a backtrace\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\n    # Meson (because it uses a separate build directory)\n    gdb build/rofi core\n```\n\n> Where the core file is located and what its exact name is different on each\n> distributions. Please consult the relevant documentation.\n\nFor more information see the rofi-debugging(5) manpage.\n\n## Install distribution\n\n### Debian or Ubuntu\n\n```bash\n    apt install rofi\n```\n\n### Fedora\n\n```bash\n    dnf install rofi\n```\n\n### ArchLinux\n\n```bash\n    pacman -S rofi\n```\n\n### Gentoo\n\nAn ebuild is available, `x11-misc/rofi`. It's up to date, but you may need to\nenable ~arch to get the latest release:\n\n```bash\n    echo 'x11-misc/rofi ~amd64' >> /etc/portage/package.accept_keywords\n```\n\nfor amd64 or:\n\n```bash\n    echo 'x11-misc/rofi ~x86' >> /etc/portage/package.accept_keywords\n```\n\nfor i386.\n\nTo install it, simply issue `emerge rofi`.\n\n### openSUSE\n\nOn both openSUSE Leap and openSUSE Tumbleweed rofi can be installed using:\n\n```bash\n    sudo zypper install rofi\n```\n\n### FreeBSD\n\n```bash\n    sudo pkg install rofi\n```\n\n### macOS\n\nOn macOS rofi can be installed via [MacPorts](https://www.macports.org):\n\n```bash\n    sudo port install rofi\n```\n\n[master-install]: https://github.com/DaveDavenport/rofi/blob/master/INSTALL.md#install-a-checkout-from-git\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<a href=\"https://github.com/davatorium/rofi/issues\"><img src=\"https://img.shields.io/github/issues/davatorium/rofi.svg\"></a>\n<a href=\"https://img.shields.io/github/forks/davatorium/rofi.svg\"><img src=\"https://img.shields.io/github/forks/davatorium/rofi.svg\"></a>\n<a href=\"https://github.com/davatorium/rofi/stargazers\"><img src=\"https://img.shields.io/github/stars/davatorium/rofi.svg\"></a>\n<a href=\"https://github.com/davatorium/rofi/releases\"><img src=\"https://img.shields.io/github/downloads/davatorium/rofi/total.svg\"></a>\n<a href=\"https://repology.org/metapackage/rofi/versions\"><img src=\"https://repology.org/badge/tiny-repos/rofi.svg\"></a>\n</p>\n\n**Please match the documentation and scripts to the version of rofi used**\n\n- [next version](https://github.com/davatorium/rofi)\n- [2.0.0](https://github.com/davatorium/rofi/tree/2.0.0)\n- [1.7.9](https://github.com/davatorium/rofi/tree/1.7.9)\n- [1.7.8](https://github.com/davatorium/rofi/tree/1.7.8)\n- [1.7.7](https://github.com/davatorium/rofi/tree/1.7.7)\n- [1.7.6](https://github.com/davatorium/rofi/tree/1.7.6)\n- [1.7.5](https://github.com/davatorium/rofi/tree/1.7.5)\n- [1.7.4](https://github.com/davatorium/rofi/tree/1.7.4)\n- [1.7.3](https://github.com/davatorium/rofi/tree/1.7.3)\n- [1.7.2](https://github.com/davatorium/rofi/tree/1.7.2)\n- [1.7.1](https://github.com/davatorium/rofi/tree/1.7.1)\n- [1.7.0](https://github.com/davatorium/rofi/tree/1.7.0)\n\nAlso see the locally installed documentation (manpages).\n\n<h1 align=\"center\"> Rofi </h1>\n<p align=\"center\"><i>A window switcher, Application launcher and dmenu replacement</i>.</p>\n\n<https://user-images.githubusercontent.com/84911063/139428874-fe182dd6-82c6-49b8-8da1-920ddda3d1ed.mp4>\n\n**Rofi** started as a clone of simpleswitcher, written by [Sean\nPringle](http://github.com/seanpringle/simpleswitcher) - a popup window\nswitcher roughly based on\n[superswitcher](http://code.google.com/p/superswitcher/). Simpleswitcher laid\nthe foundations, and therefore Sean Pringle deserves most of the credit for\nthis tool. **Rofi** (renamed, as it lost the *simple* property) has been\nextended with extra features, like an application launcher and ssh-launcher,\nand can act as a drop-in dmenu replacement, making it a very versatile tool.\nThanks to the great work of [lbonn](https://github.com/lbonn), who added\nWayland support in his fork and maintained it for years, **Rofi**\nnow officially supports Wayland (since 2025).\n\n**Rofi**, like dmenu, will provide the user with a textual list of options\nwhere one or more can be selected.\nThis can either be running an application, selecting a window, or options\nprovided by an external script.\n\n### What is rofi not?\n\nRofi is not:\n\n- A UI toolkit.\n\n- A library to be used in other applications.\n\n- An application that can support every possible use-case. It tries to be\n    generic enough to be usable by everybody.\n  - Specific functionality can be added using scripts or plugins, many exists.\n\n- Just a dmenu replacement. The dmenu functionality is a nice 'extra' to\n    **rofi**, not its main purpose.\n\n## Table of Contents\n\n- [Features](#features)\n- [Modes](#modes)\n- [Manpages](#manpage)\n- [Installation](#installation)\n- [Quickstart](#quickstart)\n  - [Usage](#usage)\n  - [Configuration](#configuration)\n  - [Themes](#themes)\n- [Screenshots](#screenshots)\n- [Wiki](#wiki)\n- [Discussion places](#discussion-places)\n\n## Features\n\nIts main features are:\n\n- Fully configurable keyboard navigation\n\n- Type to filter\n  - Tokenized: type any word in any order to filter\n  - Case insensitive (togglable) or SmartCase\n  - Support for fuzzy-, regex-, prefix-, and glob-matching\n\n- UTF-8 enabled\n  - UTF-8-aware string collating\n  - International keyboard support (\\`e -> è)\n\n- RTL language support\n\n- Cairo drawing and Pango font rendering\n\n- Built-in modes:\n  - Window switcher mode\n    - EWMH compatible WM\n    - Work arounds for i3,bspwm\n    - Wayland based WMs that follow the wlr family\n\n  - Application launcher\n\n  - Desktop file application launcher\n\n  - SSH launcher mode\n\n  - File browser\n\n  - Combi mode, allowing several modes to be merged into one list\n\n- History-based ordering — last 25 choices are ordered on top based on use\n    (optional)\n\n- Levenshtein distance or fzf like sorting of matches (optional)\n\n- Drop-in dmenu replacement\n  - Many added improvements\n\n- Easily extensible using scripts and plugins\n\n- Advanced Theming\n\n## Modes\n\n**Rofi** has several built-in modes implementing common use cases and can be\nextended by scripts (either called from\n**Rofi** or calling **Rofi**) or plugins.\n\nBelow is a list of the different modes:\n\n- **run**: launch applications from $PATH, with option to launch in terminal.\n\n- **drun**: launch applications based on desktop files. It tries to be\n    compliant to the XDG standard.\n\n- **window**: Switch between windows on an EWMH compatible window manager.\n\n- **ssh**: Connect to a remote host via ssh.\n\n- **filebrowser**: A basic file-browser for opening files.\n\n- **keys**: list internal keybindings.\n\n- **script**: Write (limited) custom mode using simple scripts.\n\n- **combi**: Combine multiple modes into one.\n\n**Rofi** is known to work on Linux and BSD.\n\n## Wayland support\n\n### Build\n\nPlease follow the [build instructions](INSTALL.md) to build rofi.\n\nWayland support is enabled by default, along with X11/xcb.\n\nrofi can also be built *without* X11/xcb or wayland, but atleast one backend\nshould be enabled:\n\n    meson build -Dxcb=disabled\n    meson build -Dwayland=disabled\n\n### Usage\n\n**Rofi** should automatically select the xcb or wayland backend depending on\nthe environment it is run on.\n\nTo force the use of the xcb backend (if enabled during build), the `-x11`\noption can be used:\n\n    rofi -x11 ...\n\n### Missing features in Wayland mode\n\nDue to the different architecture and available APIs in Wayland mode, some original rofi features are difficult or impossible to replicate\n\n- `-normal-window` flag. Though it is also considered as a toy/deprecated feature in Upstream rofi. Not impossible but would require some work.\n- `-monitor -n` for fine-grained selection of monitor to display rofi on\n- some window locations parameters work partially, `x-offset` and `y-offset` are only working from screen edges\n- fake transparency\n- window mode on KWin which implements different protocols than the wlr family\n\n### Wayland DPI\n\nOn wayland, the output is only known after the first surface is shown. This makes sizing\nrofi windows in absolute size (mm) very difficult, a problem unique for rofi,\nas the actual DPI is unknown before hand. This can be worked around by manually\npassing the right DPI via configuration system. If the `dpi` config option is\nset to `0` and only one monitor is connected rofi will use the DPI of the only\nconnected monitor or if you have multiple monitors and you specify a monitor\nname, it will use the DPI of that monitor.\n\n## Manpage\n\nFor more up to date information, please see the manpages. The other sections\nand links might have outdated information as they have relatively less\nmaintainance than the manpages. So, if you come across any issues please\nconsult manpages, [discussion](https://github.com/davatorium/rofi/discussions)\nand [issue tracker](https://github.com/davatorium/rofi/issues?q=) before filing\nnew issue.\n\n- Manpages:\n  - [rofi](doc/rofi.1.markdown)\n  - [rofi-theme](doc/rofi-theme.5.markdown)\n  - [rofi-debugging](doc/rofi-debugging.5.markdown)\n  - [rofi-script](doc/rofi-script.5.markdown)\n  - [rofi-theme-selector](doc/rofi-theme-selector.1.markdown)\n  - [rofi-thumbnails](doc/rofi-thumbnails.5.markdown)\n  - [rofi-keys](doc/rofi-keys.5.markdown)\n  - [rofi-dmenu](doc/rofi-dmenu.5.markdown)\n\n## Installation\n\nPlease see the [installation guide](INSTALL.md) for instructions on how to\ninstall **Rofi**.\n\n## Quickstart\n\n### Usage\n\n> **This section just gives a brief overview of the various options. To get the\n> full set of options see the [manpages](#manpage) section above**\n\n#### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `run` dialog:\n\n```bash\n    rofi -show run\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSpecify an ordered, comma-separated list of modes to enable. Enabled modes can\nbe changed at runtime. Default key is `Ctrl+Tab`. If no modes are specified,\nall configured modes will be enabled. To only show the `run` and `ssh`\nlauncher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n### Configuration\n\nGenerate a default configuration file\n\n```bash\nmkdir -p ~/.config/rofi\nrofi -dump-config > ~/.config/rofi/config.rasi\n```\n\nThis creates a file called `config.rasi` in the `~/.config/rofi/` folder. You\ncan modify this file to set configuration settings and modify themes.\n`config.rasi` is the file rofi looks to by default.\n\nPlease see the [configuration\nguide](https://github.com/davatorium/rofi/blob/next/CONFIG.md) for a summary of\nconfiguration options. More detailed options are provided in the manpages.\n\n### Themes\n\nPlease see the [themes\nmanpages](https://github.com/davatorium/rofi/blob/next/doc/rofi-theme.5.markdown)\nfor a detailed description.\n\nThe latest bundled themes can be found\n[here](https://github.com/davatorium/rofi/tree/next/themes).\n\n## Screenshots\n\nRezlooks:\n\n![screenshot](https://raw.githubusercontent.com/davatorium/rofi/next/releasenotes/1.6.0/icons.png)\n\nArthur:\n\n![screenshot2](https://raw.githubusercontent.com/davatorium/rofi/next/releasenotes/1.6.0/icons2.png)\n\nDefault theme:\n\n![default](https://raw.githubusercontent.com/davatorium/rofi/next/releasenotes/1.4.0/rofi-no-fzf.png)\n\n## Wiki\n\n| ❗ **The Wiki is currently unmaintained and might contain outdated data** |\n| --- |\n\n[Go to wiki](https://github.com/davatorium/rofi/wiki) .\n\n### Contents\n\n- [User scripts](https://github.com/davatorium/rofi/wiki/User-scripts)\n- [Examples](https://github.com/davatorium/rofi/wiki#examples)\n- [dmenu Specs](https://github.com/davatorium/rofi/wiki/dmenu_specs)\n- [mode Specs](https://github.com/davatorium/rofi/wiki/mode-Specs)\n- [F.A.Q.](https://github.com/davatorium/rofi/wiki/Frequently-Asked-Questions).\n- [Script mode](https://github.com/davatorium/rofi/wiki/rfc-script-mode)\n- [Creating an issue](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\n- [Creating a Pull request](https://github.com/davatorium/rofi/wiki/Creating-a-pull-request)\n\n## Discussion places\n\nThe [GitHub Discussions](https://github.com/davatorium/rofi/discussions) is the\npreferred location for discussions.\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- IRC (#rofi on irc.libera.chat)\n\n### Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/davatorium/rofi.svg)](https://starchart.cc/davatorium/rofi)\n"
  },
  {
    "path": "config/config.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"config.h\"\n#include \"rofi-types.h\"\n#include \"settings.h\"\n#include <glib.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nSettings config = {\n/** List of enabled modes. */\n/** -modes */\n#ifdef WINDOW_MODE\n    .modes = \"window,drun,run,ssh\",\n#else\n    .modes = \"drun,run,ssh\",\n#endif\n    /** Font */\n    .menu_font = \"mono 12\",\n\n    /** Whether to load and show icons */\n    .show_icons = FALSE,\n\n    /** Custom command to generate preview icons */\n    .preview_cmd = NULL,\n\n    /** Custom command to call when menu selection changes */\n    .on_selection_changed = NULL,\n    /** Custom command to call when menu mode changes */\n    .on_mode_changed = NULL,\n    /** Custom command to call when menu entry is accepted */\n    .on_entry_accepted = NULL,\n    /** Custom command to call when menu is canceled */\n    .on_menu_canceled = NULL,\n    /** Custom command to call when menu finds errors */\n    .on_menu_error = NULL,\n    /** Custom command to call when menu screenshot is taken */\n    .on_screenshot_taken = NULL,\n    /** Terminal to use. (for ssh and open in terminal) */\n    .terminal_emulator = \"rofi-sensible-terminal\",\n    .ssh_client = \"ssh\",\n    /** Command when executing ssh. */\n    .ssh_command = \"{terminal} -e {ssh-client} {host} [-p {port}]\",\n    /** Command when running */\n    .run_command = \"{cmd}\",\n    /** Command used to list executable commands. empty -> internal */\n    .run_list_command = \"\",\n    /** Command executed when running application in terminal */\n    .run_shell_command = \"{terminal} -e {cmd}\",\n    /** Command executed on accep-entry-custom for window modus */\n    .window_command = \"wmctrl -i -R {window}\",\n    /** No default icon theme, we search Adwaita and gnome as fallback */\n    .icon_theme = NULL,\n    /**\n     * Location of the window.\n     * Enumeration indicating location or gravity of window.\n     *\n     * WL_NORTH_WEST      WL_NORTH      WL_NORTH_EAST\n     *\n     * WL_EAST            WL_CENTER     WL_EAST\n     *\n     * WL_SOUTH_WEST      WL_SOUTH      WL_SOUTH_EAST\n     *\n     */\n    .location = WL_CENTER,\n    /**\n     * On Wayland, specifies the layer where rofi is rendered. Available layers are\n     * `background`, `bottom`, `top`, `overlay`. The default layer is `overlay`.\n     */\n    .wayland_layer = \"overlay\",\n    /** Y offset */\n    .y_offset = 0,\n    /** X offset */\n    .x_offset = 0,\n    /** Always show config.menu_lines lines, even if less lines are available */\n    .fixed_num_lines = TRUE,\n    /** Do not use history */\n    .disable_history = FALSE,\n    /** Programs ignored for history */\n    .ignored_prefixes = \"\",\n    /** Sort the displayed list */\n    .sort = FALSE,\n    /** Use levenshtein sorting when matching */\n    .sorting_method = \"normal\",\n    /** Case sensitivity of the search */\n    .case_sensitive = FALSE,\n    /** Case smart of the search */\n    .case_smart = FALSE,\n    /** Cycle through in the element list */\n    .cycle = TRUE,\n    /** Height of an element in #chars */\n    .element_height = 1,\n    /** Sidebar mode, show the modes */\n    .sidebar_mode = FALSE,\n    /** auto select */\n    .auto_select = FALSE,\n    /** Parse /etc/hosts file in ssh view. */\n    .parse_hosts = FALSE,\n    /** Parse ~/.ssh/known_hosts file in ssh view. */\n    .parse_known_hosts = TRUE,\n    /** Modes to combine into one view. */\n    .combi_modes = \"window,run\",\n    .tokenize = TRUE,\n    .matching = \"normal\",\n    .matching_method = MM_NORMAL,\n\n    /** Desktop entries to match in drun */\n    .drun_match_fields = \"name,generic,exec,categories,keywords\",\n    /** Only show entries in this category */\n    .drun_categories = NULL,\n    /** Exclude entries in this category */\n    .drun_exclude_categories = NULL,\n    /** Desktop entry show actions */\n    .drun_show_actions = FALSE,\n    /** Desktop format display */\n    .drun_display_format =\n        \"{name} [<span weight='light' size='small'><i>({generic})</i></span>]\",\n    /** Desktop Link launch command */\n    .drun_url_launcher = \"xdg-open\",\n\n    /** Window fields to match in window mode*/\n    .window_match_fields = \"all\",\n    /** Monitor */\n    .monitor = \"-5\",\n    /** Set filter */\n    .filter = NULL,\n    .dpi = -1,\n    .threads = 0,\n    .scroll_method = 0,\n    .window_format = \"{w}    {c}   {t}\",\n    .click_to_exit = TRUE,\n    .global_kb = FALSE,\n    .theme = NULL,\n    .plugin_path = PLUGIN_PATH,\n    .max_history_size = 25,\n    .combi_hide_mode_prefix = FALSE,\n    .combi_display_format = \"{mode} {text}\",\n\n    .matching_negate_char = '-',\n\n    .cache_dir = NULL,\n    .window_thumbnail = FALSE,\n\n    /** drun cache */\n    .drun_use_desktop_cache = FALSE,\n    .drun_reload_desktop_cache = FALSE,\n\n    /** Benchmarks */\n    .benchmark_ui = FALSE,\n\n    /** normalize match */\n    .normalize_match = FALSE,\n    /** steal focus */\n    .steal_focus = FALSE,\n    /** fallback icon */\n    .application_fallback_icon = NULL,\n    /** refilter limit in ms*/\n    .refilter_timeout_limit = 300,\n    /** workaround for broken xserver (#300 on xserver, #611) */\n    .xserver_i300_workaround = FALSE,\n    /** What browser to use for completion */\n    .completer_mode = \"filebrowser\",\n    /** Whether to enable imdkit, see #2123 */\n    .enable_imdkit = TRUE,\n};\n"
  },
  {
    "path": "data/rofi-theme-selector.desktop",
    "content": "[Desktop Entry]\nEncoding=UTF-8\nVersion=1.0\nType=Application\nTerminal=false\nExec=rofi-theme-selector\nName=Rofi Theme Selector\nIcon=rofi\n"
  },
  {
    "path": "data/rofi.desktop",
    "content": "[Desktop Entry]\nEncoding=UTF-8\nVersion=1.0\nType=Application\nTerminal=false\nExec=rofi -show\nName=Rofi\nIcon=rofi\n"
  },
  {
    "path": "doc/README.md",
    "content": "Manpages are build using [pandoc](https://pandoc.org/)\n\nManpages can be updated using the following make command:\n\n```\nmake generate-manpage\n```\n"
  },
  {
    "path": "doc/default_configuration.rasi",
    "content": "configuration {\n\n    // Timeout from user input.\n    timeout {\n        // The delay after inactivity to execute action.\n        delay: 0;\n        // The action to execute once the delay expires.\n        action: \"kb-cancel\";\n    }\n\n    // File browser mode.\n    filebrowser {\n        sorting-method:    \"name\";\n        directories-first: true;\n    }\n}\n\n@theme \"default\"\n"
  },
  {
    "path": "doc/default_theme.rasi",
    "content": "/**\n * rofi -dump-theme output.\n **/\n* {\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-active-foreground:  var(background);\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    separatorcolor:              var(foreground);\n    urgent-foreground:           var(red);\n    alternate-urgent-background: var(lightbg);\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    spacing:                     2;\n    border-color:                var(foreground);\n    normal-background:           var(background);\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-background: var(lightbg);\n    active-foreground:           var(blue);\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-background:           var(background);\n    alternate-normal-foreground: var(foreground);\n    selected-active-background:  var(blue);\n    background:                  rgba ( 253, 246, 227, 100 % );\n    selected-normal-foreground:  var(lightbg);\n    active-background:           var(background);\n    alternate-active-foreground: var(blue);\n    alternate-normal-background: var(lightbg);\n    foreground:                  rgba ( 0, 43, 54, 100 % );\n    selected-urgent-background:  var(red);\n    selected-urgent-foreground:  var(background);\n    normal-foreground:           var(foreground);\n    alternate-urgent-foreground: var(red);\n    selected-normal-background:  var(lightfg);\n}\nelement {\n    padding: 1px ;\n    spacing: 5px ;\n    border:  0;\n    cursor:  pointer;\n}\nelement normal.normal {\n    background-color: var(normal-background);\n    text-color:       var(normal-foreground);\n}\nelement normal.urgent {\n    background-color: var(urgent-background);\n    text-color:       var(urgent-foreground);\n}\nelement normal.active {\n    background-color: var(active-background);\n    text-color:       var(active-foreground);\n}\nelement selected.normal {\n    background-color: var(selected-normal-background);\n    text-color:       var(selected-normal-foreground);\n}\nelement selected.urgent {\n    background-color: var(selected-urgent-background);\n    text-color:       var(selected-urgent-foreground);\n}\nelement selected.active {\n    background-color: var(selected-active-background);\n    text-color:       var(selected-active-foreground);\n}\nelement alternate.normal {\n    background-color: var(alternate-normal-background);\n    text-color:       var(alternate-normal-foreground);\n}\nelement alternate.urgent {\n    background-color: var(alternate-urgent-background);\n    text-color:       var(alternate-urgent-foreground);\n}\nelement alternate.active {\n    background-color: var(alternate-active-background);\n    text-color:       var(alternate-active-foreground);\n}\nelement-text {\n    background-color: rgba ( 0, 0, 0, 0 % );\n    text-color:       inherit;\n    highlight:        inherit;\n    cursor:           inherit;\n}\nelement-icon {\n    background-color: rgba ( 0, 0, 0, 0 % );\n    size:             1.0000em ;\n    text-color:       inherit;\n    cursor:           inherit;\n}\nwindow {\n    padding:          5;\n    background-color: var(background);\n    border:           1;\n}\nmainbox {\n    padding: 0;\n    border:  0;\n}\nmessage {\n    padding:      1px ;\n    border-color: var(separatorcolor);\n    border:       2px dash 0px 0px ;\n}\ntextbox {\n    text-color: var(foreground);\n}\nlistview {\n    padding:      2px 0px 0px ;\n    scrollbar:    true;\n    border-color: var(separatorcolor);\n    spacing:      2px ;\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n}\nscrollbar {\n    width:        4px ;\n    padding:      0;\n    handle-width: 8px ;\n    border:       0;\n    handle-color: var(normal-foreground);\n}\nsidebar {\n    border-color: var(separatorcolor);\n    border:       2px dash 0px 0px ;\n}\nbutton {\n    spacing:    0;\n    text-color: var(normal-foreground);\n    cursor:     pointer;\n}\nbutton selected {\n    background-color: var(selected-normal-background);\n    text-color:       var(selected-normal-foreground);\n}\n\nnum-filtered-rows, num-rows {\n    text-color: grey;\n    expand:     false;\n}\ntextbox-num-sep {\n    text-color: grey;\n    expand:     false;\n    str:        \"/\";\n}\ninputbar {\n    padding:    1px;\n    spacing:    0px;\n    text-color: var(normal-foreground);\n    children:   [ prompt,textbox-prompt-colon,entry, overlay,num-filtered-rows, textbox-num-sep, num-rows, case-indicator ];\n}\noverlay {\n    background-color: var(normal-foreground);\n    foreground-color: var(normal-background);\n    text-color: var(normal-background);\n    padding: 0 0.2em;\n    margin: 0 0.2em;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: var(normal-foreground);\n}\nentry {\n    spacing:           0;\n    text-color:        var(normal-foreground);\n    placeholder-color: grey;\n    placeholder:       \"Type to filter\";\n    cursor:            text;\n}\nprompt {\n    spacing:    0;\n    text-color: var(normal-foreground);\n}\ntextbox-prompt-colon {\n    margin:     0px 0.3000em 0.0000em 0.0000em ;\n    expand:     false;\n    str:        \":\";\n    text-color: inherit;\n}\n"
  },
  {
    "path": "doc/man_filter.lua",
    "content": "local Def = {}\n\nfunction Def:new(d)\n    -- init with empty def\n    if d == nil then\n        d = {\n            start_idx = nil,\n            end_idx = nil,\n            def_par = nil,\n            content = {},\n        }\n    end\n    setmetatable(d, self)\n    self.__index = self\n    return d\nend\n\nfunction Def:init(start_idx, el)\n    self.start_idx = start_idx\n    self.def_par = el\nend\n\nfunction Def:append(el)\n    if self.start_idx ~= nil then\n        table.insert(self.content, el)\n    end\nend\n\nfunction Def:stop(end_idx)\n    if self.start_idx == nil then\n        return nil\n    end\n    local out = self:new({\n        start_idx = self.start_idx,\n        end_idx = end_idx,\n        def_par = self.def_par,\n        content = self.content,\n    })\n    self.start_idx = nil\n    self.end_idx = nil\n    self.def_par = nil\n    self.content = {}\n    return out\nend\n\nfunction Def:to_string()\n    return string.format(\"start: %d, end: %d, def_par: %s\", self.start_idx, self.end_idx, self.def_par)\nend\n\nfunction find_defs(doc)\n    local defs = {}\n    local idx = 0\n    local def = Def:new()\n\n    -- find defintions:\n    -- * start at paragraphs with `word` ...\n    -- * stop at next definition or next header\n    local filter = {\n        traverse = \"topdown\",\n        Para = function(el)\n            idx = idx + 1\n\n            local new_def_start = #el.content >= 1 and el.content[1].tag == \"Code\"\n\n            if new_def_start then\n                local newd = def:stop(idx - 1)\n                table.insert(defs, newd)\n\n                def:init(idx, el.content)\n            else\n                def:append(el)\n            end\n            return nil, false\n        end,\n        Block = function(el)\n            idx = idx + 1\n            def:append(el)\n            -- stop exploring after one nesting level\n            return nil, false\n        end,\n        Header = function(el)\n            idx = idx + 1\n            local newd = def:stop(idx - 1)\n            table.insert(defs, newd)\n            return nil, false\n        end,\n    }\n\n    doc:walk(filter)\n    local newd = def:stop(idx - 1)\n    table.insert(defs, newd)\n\n    return defs\nend\n\nfunction convert_defs(doc, defs)\n    local idx = 0\n    local out_blocks = {}\n\n    local convert_defs = {\n        traverse = \"topdown\",\n        Block = function(el)\n            idx = idx + 1\n            for _, d in ipairs(defs) do\n                if idx == d.end_idx then\n                    local dl = pandoc.DefinitionList({ { d.def_par, { d.content } } })\n                    table.insert(out_blocks, dl:walk())\n                    return {}, false\n                end\n                if idx >= d.start_idx and idx < d.end_idx then\n                    -- drop\n                    return {}, false\n                end\n            end\n            table.insert(out_blocks, el:walk())\n            return nil, false\n        end,\n    }\n\n    doc:walk(convert_defs)\n\n    return pandoc.Pandoc(out_blocks, doc.meta)\nend\n\n-- for <2.17 compatibility\n-- equivalent to `doc:walk(filter)`\nlocal function walk_doc(doc, filter)\n    local div = pandoc.Div(doc.blocks)\n    local blocks = pandoc.walk_block(div, filter).content\n    return pandoc.Pandoc(blocks, doc.meta)\nend\n\nlocal function extract_title(doc)\n    local title = {}\n    local section\n    local filter = {\n        Header = function(el)\n            local f = {\n                Str = function(el)\n                    if el.text:find(\"%(1%)\") ~= nil then\n                        section = \"General Commands Manual\"\n                    elseif el.text:find(\"%(5%)\") ~= nil then\n                        section = \"File Formats Manual\"\n                    end\n                    table.insert(title, el)\n                end,\n                Inline = function(el)\n                    table.insert(title, el)\n                end,\n            }\n            if el.level == 1 then\n                pandoc.walk_block(el, f)\n                return {} -- drop\n            end\n            return nil\n        end,\n    }\n\n    doc = walk_doc(doc, filter)\n\n    local to_inline = function(s)\n        local r = {}\n        for w in s:gmatch(\"%S+\") do\n            table.insert(r, pandoc.Str(w))\n            table.insert(r, pandoc.Space())\n        end\n        table.remove(r, #r)\n        return r\n    end\n\n    if section ~= nil then\n        for _, e in ipairs({\n            pandoc.Space(),\n            pandoc.Str(\"rofi\"),\n            pandoc.Space(),\n            pandoc.Str(\"|\"),\n            table.unpack(to_inline(section)),\n        }) do\n            table.insert(title, e)\n        end\n    end\n\n    doc.meta = pandoc.Meta({\n        title = pandoc.MetaInlines(title),\n    })\n\n    return doc\nend\n\nlocal function decrement_heading(doc)\n    local filter = {\n        Header = function(el)\n            if el.level > 1 then\n                el.level = el.level - 1\n                return el\n            end\n            return nil\n        end,\n    }\n\n    doc = walk_doc(doc, filter)\n    return doc\nend\n\nlocal function code_in_strong(doc)\n    local filter = {\n        Code = function(el)\n            return pandoc.Strong(el.text)\n        end,\n    }\n\n    doc = walk_doc(doc, filter)\n    return doc\nend\n\n--- Run filtering function through whole document\n--\n--  * find argument definitions: paragraph starting with inline code (`-arg`)\n--  * replace the paragraphs until the end of the definition with a DefinitionList\n--  * extract metadata title from main heading\n--  * decrement heading from 1 for better display\n--  * convert inline code text to Strong as usual in man pages\nfunction Pandoc(doc)\n    if PANDOC_VERSION >= pandoc.types.Version(\"2.17.0\") then\n        -- 2.17 is required for topdown traversal\n        local defs = find_defs(doc)\n        doc = convert_defs(doc, defs)\n    end\n\n    doc = extract_title(doc)\n\n    doc = decrement_heading(doc)\n\n    doc = code_in_strong(doc)\n\n    return doc\nend\n"
  },
  {
    "path": "doc/meson.build",
    "content": "man_files = [\n    'rofi.1',\n    'rofi-sensible-terminal.1',\n    'rofi-theme-selector.1',\n    'rofi-actions.5',\n    'rofi-debugging.5',\n    'rofi-dmenu.5',\n    'rofi-keys.5',\n    'rofi-script.5',\n    'rofi-theme.5',\n    'rofi-thumbnails.5',\n]\n\nfs = import('fs')\n\npandoc = find_program('pandoc', required: false, version: '>=2.9')\n\nif pandoc.found()\n    man_targets = []\n    cp_cmds = []\n    foreach f: man_files\n        section_number = f.split('.')[1]\n        install_dest = join_paths(get_option('prefix'), get_option('mandir'), 'man' + section_number)\n\n        man_targets += custom_target(f,\n            input: ['.'.join([f, 'markdown']), 'man_filter.lua'],\n            output: f,\n            command: [ 'pandoc', '--standalone', '--to=man',\n                '--lua-filter', '@INPUT1@',\n                '-f', 'markdown-tex_math_dollars',\n                '@INPUT0@', '-o', '@OUTPUT@' ],\n            install: true,\n            install_dir: install_dest,\n            build_by_default: true,\n        )\n    endforeach\n\n    run_target('generate-manpage', command: ['true'], depends: man_targets)\nelse\n    man_missing = false\n    foreach f: man_files\n        if not fs.is_file(f)\n            man_missing = true\n        endif\n    endforeach\n\n    if man_missing\n        warning('Man files cannot be generated and not present in source directory, they will not be installed')\n    else\n        install_man(man_files)\n    endif\nendif\n\ndoxy_conf = configuration_data()\ndoxy_conf.set('PACKAGE', meson.project_name())\ndoxy_conf.set('VERSION', meson.project_version())\ndoxy_conf.set('abs_builddir', join_paths(meson.project_build_root(), meson.current_build_dir()))\ndoxy_conf.set('abs_top_srcdir', meson.project_source_root())\n\ndoxyfile = configure_file(\n    input: 'rofi.doxy.in',\n    output: 'rofi.doxy',\n    configuration: doxy_conf,\n)\n\ndoxygen = find_program('doxygen', required: false)\nif doxygen.found()\n    html_target = custom_target('doxy',\n        input: doxyfile,\n        output: 'html',\n        command: [doxygen, doxyfile],\n        install: false,\n    )\nendif\n"
  },
  {
    "path": "doc/rofi-actions.5.markdown",
    "content": "# rofi-actions(5)\n\n## NAME\n\n**rofi-actions** - Custom commands following interaction with rofi menus\n\n## DESCRIPTION\n\n**rofi** allows to set custom commands or scripts to be executed when some actions are performed in the menu, such as changing selection, accepting an entry or canceling.\n\nThis makes it possible for example to play sound effects or read aloud menu entries on selection.\n\n## USAGE\n\nFollowing is the list of rofi flags for specifying custom commands or scripts to execute on supported actions:\n\n`-on-selection-changed` *cmd*\n\nCommand or script to run when the current selection changes. Selected text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-entry-accepted` *cmd*\n\nCommand or script to run when a menu entry is accepted. Accepted text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-mode-changed` *cmd*\n\nCommand or script to run when the menu mode (e.g. drun,window,ssh...) is changed.\n\n`-on-menu-canceled` *cmd*\n\nCommand or script to run when the menu is canceled.\n\n`-on-menu-error` *cmd*\n\nCommand or script to run when an error menu is shown (e.g. `rofi -e \"error message\"`). Error text is forwarded to the command replacing the pattern *{error}*.\n\n`-on-screenshot-taken` *cmd*\n\nCommand or script to run when a screenshot of rofi is taken. Screenshot path is forwarded to the command replacing the pattern *{path}*.\n\n### Example usage\n\nRofi command line:\n\n```bash\nrofi -on-selection-changed \"/path/to/select.sh {entry}\" \\\n     -on-entry-accepted \"/path/to/accept.sh {entry}\" \\\n     -on-menu-canceled \"/path/to/exit.sh\" \\\n     -on-mode-changed \"/path/to/change.sh\" \\\n     -on-menu-error \"/path/to/error.sh {error}\" \\\n     -on-screenshot-taken \"/path/to/camera.sh {path}\" \\\n     -show drun\n```\n\nRofi config file:\n\n```css\nconfiguration {\n    on-selection-changed: \"/path/to/select.sh {entry}\";\n    on-entry-accepted: \"/path/to/accept.sh {entry}\";\n    on-menu-canceled: \"/path/to/exit.sh\";\n    on-mode-changed: \"/path/to/change.sh\";\n    on-menu-error: \"/path/to/error.sh {error}\";\n    on-screenshot-taken: \"/path/to/camera.sh {path}\";\n}\n```\n\n### Play sound effects\n\nHere's an example bash script that plays a sound effect using `aplay` when the current selection is changed:\n\n```bash\n#!/bin/bash\n\ncoproc aplay -q $HOME/Music/selecting_an_item.wav\n```\n\nThe use of `coproc` for playing sounds is suggested, otherwise the rofi process will wait for sounds to end playback before exiting.\n\n### Read aloud\n\nHere's an example bash script that reads aloud currently selected entries using `espeak`:\n\n```bash\n#!/bin/bash\n\nkillall espeak\necho \"selected: $@\" | espeak\n```\n"
  },
  {
    "path": "doc/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "doc/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://docs.gtk.org/Pango/pango_markup.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "doc/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-transpose-chars`\n\nTranspose (swap) the two characters before the cursor\n\nDefault:  Control+t\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n`kb-matcher-up`\n\nSelect the next matcher.\n\nDefault: Super+equal\n\n`kb-matcher-down`\n\nSelect the previous matcher.\n\nDefault: Super+minus\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "doc/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **3**: Deleted an entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n### `ROFI_INPUT`\n\nThe original input string from user.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared.\n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\n-   **switch-mode**:  Switches to the given mode if enabled, otherwise ignored.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row. Multiple fallback icons can be specified using comma-separated values.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder,inode-directory\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "doc/rofi-sensible-terminal.1.markdown",
    "content": "# rofi-sensible-terminal(1)\n\n## NAME\n\n**rofi-sensible-terminal** -  launches $TERMINAL with fallbacks\n\n## SYNOPSIS\n\nrofi-sensible-terminal [arguments]\n\n## DESCRIPTION\n\nrofi-sensible-terminal is invoked in the rofi default config to start a terminal. This\nwrapper script is necessary since there is no distribution-independent terminal launcher\n(but for example Debian has x-terminal-emulator). Distribution packagers are responsible for\nshipping this script in a way which is appropriate for the distribution.\n\nIt tries to start one of the following (in that order):\n\n* `$TERMINAL` (this is a non-standard variable)\n* x-terminal-emulator\n* urxvt\n* rxvt\n* st\n* terminology\n* qterminal\n* Eterm\n* aterm\n* uxterm\n* xterm\n* roxterm\n* xfce4-terminal.wrapper\n* mate-terminal\n* lxterminal\n* konsole\n* alacritty\n* kitty\n* wezterm\n* foot\n\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nDave Davenport and contributors\n\nCopied script from i3:\nMichael Stapelberg and contributors\n"
  },
  {
    "path": "doc/rofi-theme-selector.1.markdown",
    "content": "# rofi-theme-selector(1)\n\n## NAME\n\n**rofi-theme-selector** - Preview and apply themes for **rofi**\n\n## DESCRIPTION\n\n**rofi-theme-selector** is a bash/rofi script to preview and apply themes for\n**rofi**. It's part of any installation of **rofi**.\n\n## USAGE\n\n### Running rofi-theme-selector\n\n**rofi-theme-selector** shows a list of all available themes in a **rofi**\nwindow. It lets you preview each theme with the Enter key and apply the theme\nto your **rofi** configuration file with Alt+a.\n\n## Theme directories\n\n**rofi-theme-selector** searches the following directories for themes:\n\n- ${PREFIX}/share/rofi/themes\n- $XDG_CONFIG_HOME/rofi/themes\n- $XDG_DATA_HOME/share/rofi/themes\n\n${PREFIX} reflects the install location of rofi. In most cases this will be\n\"/usr\".<br>\n$XDG_CONFIG_HOME is normally unset. Default path is \"$HOME/.config\".<br>\n$XDG_DATA_HOME is normally unset. Default path is \"$HOME/.local/share\".\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nQball Cow qball@gmpclient.org<br>\nRasmus Steinke rasi@xssn.at\n"
  },
  {
    "path": "doc/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also customize the cursor's color, width, and choose to hide it when the input box is empty. You could, for example, create a crimson block cursor that only appears when text is entered, like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n  hide-cursor-on-empty: true;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels and `hide-cursor-on-empty` is set to false.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n\n- Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n- Format: url(\"path to image\");\n\n- Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n- Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n- Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n- Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n- Format: `#{HEX}{3}` (rgb)\n\n- Format: `#{HEX}{4}` (rgba)\n\n- Format: `#{HEX}{6}` (rrggbb)\n\n- Format: `#{HEX}{8}` (rrggbbaa)\n\n- Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n- Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n- Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n- Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n- `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n- `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n- `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n- `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n- `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\n\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\n\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue\n- `ceil`   : Round up lvalue to the next multiple of rvalue\n- `round`  : Round lvalue to the next multiple of rvalue\n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n- Format: `{Integer}`\n\n- Format: `{Distance}`\n\n- Format: `{Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  - `overlay`: the overlay widget.\n\n  - `mainbox`: The mainbox box.\n\n  - `inputbar`: The input bar box.\n    - `box`: the horizontal @box packing the widgets\n\n    - `case-indicator`: the case/sort indicator @textbox\n\n    - `prompt`: the prompt @textbox\n\n    - `entry`: the main entry @textbox\n\n    - `num-rows`: Shows the total number of rows.\n\n    - `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n    - `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n    - `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n  - `listview`: The listview.\n\n    - `scrollbar`: the listview scrollbar\n\n    - `element`: a box in the listview holding the entries\n\n      - `element-icon`: the widget in the listview's entry showing the\n   (optional) icon\n\n      - `element-index`: the widget in the listview's entry\n   keybindable index (1,2,3..0)\n\n      - `element-text`: the widget in the listview's entry showing the\n   text.\n\n  - `mode-switcher`: the main horizontal @box packing the buttons.\n    - `button`: the buttons @textbox for each mode\n\n  - `message`: The container holding the textbox.\n    - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n### all widgets\n\n- **enabled**:           enable/disable rendering of the widget\n\n- **padding**:           padding\n    Padding on the inside of the widget\n\n- **margin**:            padding\n    Margin on the outside of the widget\n\n- **border**:            border\n    Border around the widget (between padding and margin)/\n\n- **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n- border-aa:  boolean\n    Disable aliasing on the border line. Disabling fixes some drawing issues because of nvidia broken driver workaround.\n\n- border-disable-nvidia-workaround: boolean\n    Disable work-around for nvidia driver breaking.\n\n- **background-color**:  color\n    Background color\n\n- **background-image**:  image\n    Background image\n\n- **border-color**:      color\n    Color of the border\n\n- **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n- **font**:            string\n    The font used in the window\n\n- **transparency**:    string\n    Indicating if transparency should be used and what type:\n  - **real** - True transparency. Only works with a compositor.\n  - **background** - Take a screenshot of the background image and use that.\n  - **screenshot** - Take a screenshot of the screen and use that.\n  - **Path** to png file - Use an image.\n\n- **location**:       position\n      The place of the anchor on the monitor\n\n- **anchor**:         anchor\n      The anchor position on the window\n\n- **fullscreen**:     boolean Window is fullscreen.\n\n- **width**:          distance The width of the window\n\n- **x-offset**:       distance\n\n- **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n- **handle-rounded-corners**:     boolean for rounded scrollbar\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n- **background-color**:  color\n\n- **border-color**:      the color used for the border around the widget.\n\n- **font**:              the font used by this textbox (string).\n\n- **str**/**content**:   the string to display by this textbox (string).\n\n- **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n- **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n- **text-color**:        the text color to use.\n\n- **text-transform**:    text style {color} for the whole text.\n\n- **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n- **width**:             override the desired width for the textbox.\n\n- **content**:           Set the displayed text (String).\n\n- **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n- **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n- **placeholder-color**: Color of the placeholder text.\n\n- **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n- **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n- **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n- **cursor-width**:      The width of the cursor.\n\n- **cursor-color**:      The color used to draw the cursor.\n\n- **hide-cursor-on-empty**: Hides the cursor when the search field is empty.\n    (Boolean)\n\n- **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n- **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n- **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n- **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n- **text-outline-width**: The width of the border around the text.  (Double)\n\n- **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n\n- **columns**:         integer Number of columns to show (at least 1)\n\n- **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n- **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n- **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n- **scrollbar-width**: distance Width of the scrollbar\n\n- **cycle**:           boolean When navigating, it should wrap around\n\n- **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n- **lines**:           integer Number of rows to show in the list view.\n\n- **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n- **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n- **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n- **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n- **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n### Overlay widget\n\n- **timeout**: The time the widget is visible when showing a temporary message.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n- 0 or more `element` widgets of the type box.\n\n- An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n>\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nIf the `tint`  property is set with a white, the icons is greyscale. If\nanother color is set, the icon is tinted to that color.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n- Content - The content of the widget.\n\n- Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n- Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n- Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling\n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\n\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe commandline option `-theme` is handled similarly to `@theme`.\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.\nIt will first look for files with `.rasi`, then for files with `.rasinc`.\n\nIf you want to do an optional import, e.g. no error when the file does not exists, you can do:\n\n```css\n?import \"myfile\"\n```\n\nThis still throws an error on syntax error, but won't abort parsing if file does not exists.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "doc/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "doc/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n- System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n- Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n- Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n dpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-info`\n\nThe info option shows useful information to include when reporting an issue.\nThis includes compile time options, detected monitors and more. Please check\nthe output for any personal information before posting online.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-wayland-layer` *layer*\n\nOn Wayland, specifies the layer where rofi is rendered. Available layers are\n`background`, `bottom`, `top`, `overlay`. The default layer is `overlay`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-case-smart`\n\nStart in case-smart mode behave like vim's `smartcase`, which determines\ncase-sensitivity by input.  When enabled, this will suppress `-case-sensitive`\nconfig.\n\nDefault: disabled.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\n\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nMultiple matching methods can be specified in a comma separated list.\nThe matching up/down keybinding allows cycling through at runtime.\n\nNote: glob matching might be slow for larger lists\n\n`-[no-]tokenize`\n\nTokenize the input into words, each word is matched separately with each entry.\nIf enabled the search `test this` will match the entry `this test`.\n\nDefault: enabled\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-exclude-categories` *category1*,*category2*\n\nExclude desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nFor Wayland, the list of accepted fields is different:\n\n- **title**: window's title\n- **app-id**: Wayland Application ID or XWayland window's class\n- **class**: same as app-id\n- **all**: all of the above\n\nDefault: *all*\n\n`-matching-negate-char` *string*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable. It takes the first ASCII character from the string.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines.\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n- **-1**: the currently focused monitor.\n\n- **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n- **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n- **-4**: the monitor with the focused window.\n\n- **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to theme file, or name of an installed theme. See **rofi-theme(5)** manpage\non how themes are resolved.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\nOn X11:\n\n- If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n- If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\nOn Wayland:\n\n- If set to `0` or `1`, it tries to auto-detect if there is one monitor, or if\nthere is a `-monitor` name specified.\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-global-kb`\n`-no-global-kb`\n\n(wayland) Override the compositor's keybindings, so that **rofi** can re-use them.\n\nDefault: *disabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n      /** Disable DBusActivatable */\n      DBusActivatable: false;\n   }\n}\n```\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- `` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n- Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n- drun: It uses the icon set in the desktop file.\n\n- run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n## Hyprland\n\nHyprland's animations make the launching of **Rofi** feel slower then needed.\nTo avoid this, add the following rule to your hyprland.conf file:\n\n```\nlayerrule = noanim,^(rofi)$\n```\n\nFor hyprland >= 0.53.0:\n\n```\nlayerrule {\n    name = fix-rofi\n    match:namespace = rofi\n    no_anim = true\n }\n\n```\n\nThis disables the animations on the **Rofi** window.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "doc/rofi.doxy.in",
    "content": "# Doxyfile 1.12.0\n\n# This file describes the settings to be used by the documentation system\n# Doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n#\n# Note:\n#\n# Use Doxygen to compare the used configuration file with the template\n# configuration file:\n# doxygen -x [configFile]\n# Use Doxygen to compare the used configuration file with the template\n# configuration file without replacing the environment variables or CMake type\n# replacement variables:\n# doxygen -x_noenv [configFile]\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the configuration\n# file that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# https://www.gnu.org/software/libiconv/ for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = @PACKAGE@\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = @VERSION@\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          =\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           =\n\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where Doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = @abs_builddir@/html/\n\n# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096\n# sub-directories (in 2 levels) under the output directory of each output format\n# and will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding Doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to\n# control the number of sub-directories.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# Controls the number of sub-directories that will be created when\n# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every\n# level increment doubles the number of directories, resulting in 4096\n# directories at level 8 which is the default and also the maximum value. The\n# sub-directories are organized in 2 levels, the first level always has a fixed\n# number of 16 directories.\n# Minimum value: 0, maximum value: 8, default value: 8.\n# This tag requires that the tag CREATE_SUBDIRS is set to YES.\n\nCREATE_SUBDIRS_LEVEL   = 8\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by Doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,\n# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English\n# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,\n# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with\n# English messages), Korean, Korean-en (Korean with English messages), Latvian,\n# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,\n# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,\n# Swedish, Turkish, Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \"The $name class\" \\\n                         \"The $name widget\" \\\n                         \"The $name file\" \\\n                         is \\\n                         provides \\\n                         specifies \\\n                         contains \\\n                         represents \\\n                         a \\\n                         an \\\n                         the\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# Doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = YES\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which Doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where Doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line\n# such as\n# /***************\n# as being the beginning of a Javadoc-style comment \"banner\". If set to NO, the\n# Javadoc-style will behave just like regular comments and it will not be\n# interpreted by Doxygen.\n# The default value is: NO.\n\nJAVADOC_BANNER         = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# By default Python docstrings are displayed as preformatted text and Doxygen's\n# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the\n# Doxygen's special commands can be used and the contents of the docstring\n# documentation blocks is shown as Doxygen documentation.\n# The default value is: YES.\n\nPYTHON_DOCSTRING       = YES\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 8\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:^^\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". Note that you cannot put \\n's in the value part of an alias\n# to insert newlines (in the resulting output). You can put ^^ in the value part\n# of an alias to insert a newline as if a physical newline was in the original\n# file. When you need a literal { or } or , in the value part of an alias you\n# have to escape them by means of a backslash (\\), this can lead to conflicts\n# with the commands \\{ and \\} for these it is advised to use the version @{ and\n# @} or use a double escape (\\\\{ and \\\\})\n\nALIASES                =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice\n# sources only. Doxygen will then generate output that is more tailored for that\n# language. For instance, namespaces will be presented as modules, types will be\n# separated into more groups, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_SLICE  = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript,\n# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,\n# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:\n# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser\n# tries to guess whether the code is fixed or free formatted code, this is the\n# default for Fortran type files). For instance to make Doxygen treat .inc files\n# as Fortran files (default is PHP), and .f files as C (default is Fortran),\n# use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by Doxygen. When specifying no_extension you should add\n# * to the FILE_PATTERNS.\n#\n# Note see also the list of default file extension mappings.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See https://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by Doxygen, so you can\n# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up\n# to that level are automatically included in the table of contents, even if\n# they do not have an id attribute.\n# Note: This feature currently applies only to Markdown headings.\n# Minimum value: 0, maximum value: 99, default value: 6.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nTOC_INCLUDE_HEADINGS   = 6\n\n# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to\n# generate identifiers for the Markdown headings. Note: Every identifier is\n# unique.\n# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a\n# sequence number starting at 0 and GITHUB use the lower case version of title\n# with any whitespace replaced by '-' and punctuation characters removed.\n# The default value is: DOXYGEN.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nMARKDOWN_ID_STYLE      = DOXYGEN\n\n# When enabled Doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let Doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also makes the inheritance and\n# collaboration diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse\n# them like normal C++ but will assume all classes use public instead of private\n# inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# Doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then Doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# Doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run Doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use\n# during processing. When set to 0 Doxygen will based this on the number of\n# cores available in the system. You can set it explicitly to a value larger\n# than 0 to get more control over the balance between CPU load and processing\n# speed. At this moment only the input processing can be done using multiple\n# threads. Since this is still an experimental feature the default is set to 1,\n# which effectively disables parallel processing. Please report any issues you\n# encounter. Generating dot graphs in parallel is controlled by the\n# DOT_NUM_THREADS setting.\n# Minimum value: 0, maximum value: 32, default value: 1.\n\nNUM_PROC_THREADS       = 1\n\n# If the TIMESTAMP tag is set different from NO then each generated page will\n# contain the date or date and time when the page was generated. Setting this to\n# NO can help when comparing the output of multiple runs.\n# Possible values are: YES, NO, DATETIME and DATE.\n# The default value is: NO.\n\nTIMESTAMP              = NO\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = YES\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = YES\n\n# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual\n# methods of a class will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIV_VIRTUAL   = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = YES\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If this flag is set to YES, the name of an unnamed parameter in a declaration\n# will be determined by the corresponding definition. By default unnamed\n# parameters remain unnamed in the output.\n# The default value is: YES.\n\nRESOLVE_UNNAMED_PARAMS = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# will also hide undocumented C++ concepts if enabled. This option has no effect\n# if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend\n# declarations. If set to NO, these declarations will be included in the\n# documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be\n# able to match the capabilities of the underlying filesystem. In case the\n# filesystem is case sensitive (i.e. it supports files in the same directory\n# whose names only differ in casing), the option must be set to YES to properly\n# deal with such files in case they appear in the input. For filesystems that\n# are not case sensitive the option should be set to NO to properly deal with\n# output files written for symbols that only differ in casing, such as for two\n# classes, one named CLASS and the other named Class, and to also support\n# references to files without having to specify the exact matching casing. On\n# Windows (including Cygwin) and macOS, users should typically set this option\n# to NO, whereas on Linux or other Unix flavors it should typically be set to\n# YES.\n# Possible values are: SYSTEM, NO and YES.\n# The default value is: SYSTEM.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class\n# will show which file needs to be included to use the class.\n# The default value is: YES.\n\nSHOW_HEADERFILE        = YES\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# Doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by Doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by Doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents Doxygen's defaults, run Doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file. See also section \"Changing the\n# layout of pages\" for information.\n#\n# Note that if you run Doxygen from a directory containing a file called\n# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by Doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for\n# potential errors in the documentation, such as documenting some parameters in\n# a documented function twice, or documenting parameters that don't exist or\n# using markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete\n# function parameter documentation. If set to NO, Doxygen will accept that some\n# parameters have no documentation without warning.\n# The default value is: YES.\n\nWARN_IF_INCOMPLETE_DOC = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, Doxygen will only warn about wrong parameter\n# documentation, but not about the absence of documentation. If EXTRACT_ALL is\n# set to YES then this flag will automatically be disabled. See also\n# WARN_IF_INCOMPLETE_DOC\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = YES\n\n# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about\n# undocumented enumeration values. If set to NO, Doxygen will accept\n# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: NO.\n\nWARN_IF_UNDOC_ENUM_VAL = NO\n\n# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when\n# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS\n# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but\n# at the end of the Doxygen process Doxygen will return with a non-zero status.\n# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves\n# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not\n# write the warning messages in between other messages but write them at the end\n# of a run, in case a WARN_LOGFILE is defined the warning messages will be\n# besides being in the defined file also be shown at the end of a run, unless\n# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case\n# the behavior will remain as with the setting FAIL_ON_WARNINGS.\n# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that Doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# See also: WARN_LINE_FORMAT\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# In the $text part of the WARN_FORMAT command it is possible that a reference\n# to a more specific place is given. To make it easier to jump to this place\n# (outside of Doxygen) the user can define a custom \"cut\" / \"paste\" string.\n# Example:\n# WARN_LINE_FORMAT = \"'vi $file +$line'\"\n# See also: WARN_FORMAT\n# The default value is: at line $line of file $file.\n\nWARN_LINE_FORMAT       = \"at line $line of file $file\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr). In case the file specified cannot be opened for writing the\n# warning and error messages are written to standard error. When as file - is\n# specified the warning and error messages are written to standard output\n# (stdout).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = @abs_top_srcdir@/source/ \\\n                         @abs_top_srcdir@/include/\n\n# This tag can be used to specify the character encoding of the source files\n# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see:\n# https://www.gnu.org/software/libiconv/) for the list of possible encodings.\n# See also: INPUT_FILE_ENCODING\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# This tag can be used to specify the character encoding of the source files\n# that Doxygen parses The INPUT_FILE_ENCODING tag can be used to specify\n# character encoding on a per file pattern basis. Doxygen will compare the file\n# name with each pattern and apply the encoding instead of the default\n# INPUT_ENCODING) if there is a match. The character encodings are a list of the\n# form: pattern=encoding (like *.php=ISO-8859-1).\n# See also: INPUT_ENCODING for further information on supported encodings.\n\nINPUT_FILE_ENCODING    =\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by Doxygen.\n#\n# Note the list of default checked file patterns might differ from the list of\n# default file extension mappings.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,\n# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,\n# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,\n# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to\n# be provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,\n# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.\n\nFILE_PATTERNS          = *.h \\\n                         *.c\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which Doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# ANamespace::AClass, ANamespace::*Test\n\nEXCLUDE_SYMBOLS        =\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = *.c\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = YES\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that Doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that Doxygen will use the data processed and written to standard output\n# for further processing, therefore nothing else, like debug statements or used\n# commands (so in case of a Windows batch file always use @echo OFF), should be\n# written to standard output.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by Doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by Doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the Doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE =\n\n# The Fortran standard specifies that for fixed formatted Fortran code all\n# characters from position 72 are to be considered as comment. A common\n# extension is to allow longer lines before the automatic comment starts. The\n# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can\n# be processed before the automatic comment starts.\n# Minimum value: 7, maximum value: 10000, default value: 72.\n\nFORTRAN_COMMENT_AFTER  = 72\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = YES\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# multi-line macros, enums or list initialized variables directly into the\n# documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# entity all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of Doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see https://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by Doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES then Doxygen will use the\n# clang parser (see:\n# http://clang.llvm.org/) for more accurate parsing at the cost of reduced\n# performance. This can be particularly helpful with template rich C++ code for\n# which Doxygen's built-in parser lacks the necessary type information.\n# Note: The availability of this option depends on whether or not Doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = NO\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS\n# tag is set to YES then Doxygen will add the directory of each input to the\n# include path.\n# The default value is: YES.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_ADD_INC_PATHS    = YES\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by Doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          =\n\n# If clang assisted parsing is enabled you can provide the clang parser with the\n# path to the directory containing a file called compile_commands.json. This\n# file is the compilation database (see:\n# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the\n# options used when the source files were built. This is equivalent to\n# specifying the -p option to a clang tool, such as clang-check. These options\n# will then be passed to the parser. Any options specified with CLANG_OPTIONS\n# will be added as well.\n# Note: The availability of this option depends on whether or not Doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n\nCLANG_DATABASE_PATH    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = NO\n\n# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)\n# that should be ignored while generating the index headers. The IGNORE_PREFIX\n# tag works for classes, function and member names. The entity will be placed in\n# the alphabetical list under the first letter of the entity name that remains\n# after removing the prefix.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank Doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that Doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that Doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of Doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank Doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that Doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank Doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that Doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by Doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# Note: Since the styling of scrollbars can currently not be overruled in\n# Webkit/Chromium, the styling will be left out of the default doxygen.css if\n# one or more extra stylesheets have been specified. So if scrollbar\n# customization is desired it has to be added explicitly. For an example see the\n# documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output\n# should be rendered with a dark or light theme.\n# Possible values are: LIGHT always generates light mode output, DARK always\n# generates dark mode output, AUTO_LIGHT automatically sets the mode according\n# to the user preference, uses light mode if no preference is set (the default),\n# AUTO_DARK automatically sets the mode according to the user preference, uses\n# dark mode if no preference is set and TOGGLE allows a user to switch between\n# light and dark mode via a button.\n# The default value is: AUTO_LIGHT.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE        = AUTO_LIGHT\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a color-wheel, see\n# https://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use gray-scales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML\n# documentation will contain a main index with vertical navigation menus that\n# are dynamically created via JavaScript. If disabled, the navigation index will\n# consists of multiple levels of tabs that are statically embedded in every HTML\n# page. Disable this option to support browsers that do not have JavaScript,\n# like the Qt help browser.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_MENUS     = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be\n# dynamically folded and expanded in the generated HTML source code.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_CODE_FOLDING      = YES\n\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see:\n# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To\n# create a documentation set, Doxygen will generate a Makefile in the HTML\n# output directory. Running make will produce the docset in that directory and\n# running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy\n# genXcode/_index.html for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag determines the URL of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDURL         =\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# on Windows. In the beginning of 2021 Microsoft took the original page, with\n# a.o. the download links, offline the HTML help workshop was already many years\n# in maintenance mode). You can download the HTML help workshop from the web\n# archives at Installation executable (see:\n# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo\n# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# Doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the main .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# The SITEMAP_URL tag is used to specify the full URL of the place where the\n# generated documentation will be placed on the server by the user during the\n# deployment of the documentation. The generated sitemap is called sitemap.xml\n# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL\n# is specified no sitemap is generated. For information about the sitemap\n# protocol see https://www.sitemaps.org\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSITEMAP_URL            =\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location (absolute path\n# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to\n# run qhelpgenerator on the generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine tune the look of the index (see \"Fine-tuning the output\"). As an\n# example, the default style sheet generated by Doxygen has an example that\n# shows how to put an image at the root of the tree instead of the PROJECT_NAME.\n# Since the tree basically has the same information as the tab index, you could\n# consider setting DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = YES\n\n# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the\n# FULL_SIDEBAR option determines if the side bar is limited to only the treeview\n# area (value NO) or if it should extend to the full height of the window (value\n# YES). Setting this to YES gives a layout similar to\n# https://docs.readthedocs.io with more room for contents, but less room for the\n# project logo, title, and description. If either GENERATE_TREEVIEW or\n# DISABLE_INDEX is set to NO, this option has no effect.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFULL_SIDEBAR           = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# Doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email\n# addresses.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nOBFUSCATE_EMAILS       = YES\n\n# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg\n# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see\n# https://inkscape.org) to generate formulas as SVG images instead of PNGs for\n# the HTML output. These images will generally look nicer at scaled resolutions.\n# Possible values are: png (the default) and svg (looks nicer but requires the\n# pdf2svg or inkscape tool).\n# The default value is: png.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FORMULA_FORMAT    = png\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# Doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# The FORMULA_MACROFILE can contain LaTeX \\newcommand and \\renewcommand commands\n# to create new LaTeX commands to be used in formulas as building blocks. See\n# the section \"Including formulas\" for details.\n\nFORMULA_MACROFILE      =\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# https://www.mathjax.org) which uses client side JavaScript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.\n# Note that the different versions of MathJax have different requirements with\n# regards to the different settings, so it is possible that also other MathJax\n# settings have to be changed when switching between the different MathJax\n# versions.\n# Possible values are: MathJax_2 and MathJax_3.\n# The default value is: MathJax_2.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_VERSION        = MathJax_2\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. For more details about the output format see MathJax\n# version 2 (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3\n# (see:\n# http://docs.mathjax.org/en/latest/web/components/output.html).\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility. This is the name for Mathjax version 2, for MathJax version 3\n# this will be translated into chtml), NativeMML (i.e. MathML. Only supported\n# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This\n# is the name for Mathjax version 3, for MathJax version 2 this will be\n# translated into HTML-CSS) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from https://www.mathjax.org before deployment. The default value is:\n# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2\n# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# for MathJax version 2 (see\n# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# For example for MathJax version 3 (see\n# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):\n# MATHJAX_EXTENSIONS = ams\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for\n# the HTML output. The underlying search engine uses JavaScript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the JavaScript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = NO\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using JavaScript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, Doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled Doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/). See the section \"External Indexing and Searching\" for\n# details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through Doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, Doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when not enabling USE_PDFLATEX the default is latex when enabling\n# USE_PDFLATEX the default is pdflatex and when in the later case latex is\n# chosen this is overwritten by pdflatex. For specific output languages the\n# default can have been set differently, this depends on the implementation of\n# the output language.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# Note: This tag is used in the Makefile / make.bat.\n# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file\n# (.tex).\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to\n# generate index for LaTeX. In case there is no backslash (\\) as first character\n# it will be automatically added in the LaTeX code.\n# Note: This tag is used in the generated output file (.tex).\n# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.\n# The default value is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_MAKEINDEX_CMD    = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, Doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for\n# the generated LaTeX document. The header should contain everything until the\n# first chapter. If it is left blank Doxygen will generate a standard header. It\n# is highly recommended to start with a default header using\n# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty\n# and then modify the file new_header.tex. See also section \"Doxygen usage\" for\n# information on how to generate the default header that Doxygen normally uses.\n#\n# Note: Only use a user-defined header if you know what you are doing!\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of Doxygen. The following\n# commands have a special meaning inside the header (and footer): For a\n# description of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for\n# the generated LaTeX document. The footer should contain everything after the\n# last chapter. If it is left blank Doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer. See also section \"Doxygen\n# usage\" for information on how to generate the default footer that Doxygen\n# normally uses. Note: Only use a user-defined footer if you know what you are\n# doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by Doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, Doxygen will use the engine as\n# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX\n# files. Set this option to YES, to get a higher quality PDF documentation.\n#\n# See also section LATEX_CMD_NAME for selecting the engine.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.\n# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch\n# mode nothing is printed on the terminal, errors are scrolled as if <return> is\n# hit at every error; missing files that TeX tries to input or request from\n# keyboard input (\\read on a not open input stream) cause the job to abort,\n# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,\n# but there is no possibility of user interaction just like in batch mode,\n# SCROLL In scroll mode, TeX will stop only for missing files to input or if\n# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at\n# each error, asking for user intervention.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then Doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# https://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)\n# path from which the emoji images will be read. If a relative path is entered,\n# it will be relative to the LATEX_OUTPUT directory. If left blank the\n# LATEX_OUTPUT directory will be used.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EMOJI_DIRECTORY  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, Doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, Doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to Doxygen's\n# configuration file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that Doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to Doxygen's configuration file. A template extensions file can be\n# generated using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, Doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, Doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = YES\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, Doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, Doxygen will include\n# namespace members in file scope as well, matching the HTML output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_NS_MEMB_FILE_SCOPE = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, Doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, Doxygen will generate an\n# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures\n# the structure of the code including all documentation. Note that this feature\n# is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to Sqlite3 output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_SQLITE3 tag is set to YES Doxygen will generate a Sqlite3\n# database with symbols found by Doxygen stored in tables.\n# The default value is: NO.\n\nGENERATE_SQLITE3       = NO\n\n# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be\n# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put\n# in front of it.\n# The default directory is: sqlite3.\n# This tag requires that the tag GENERATE_SQLITE3 is set to YES.\n\nSQLITE3_OUTPUT         = sqlite3\n\n# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db\n# database file will be recreated with each Doxygen run. If set to NO, Doxygen\n# will warn if a database file is already found and not modify it.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_SQLITE3 is set to YES.\n\nSQLITE3_RECREATE_DB    = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, Doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, Doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, Doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, Doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of\n# RECURSIVE has no effect here.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then Doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which Doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, Doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces\n# will be listed in the class and namespace index. If set to NO, only the\n# inherited external classes will be listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the topic index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to diagram generator tools\n#---------------------------------------------------------------------------\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then Doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: NO.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations Doxygen is allowed\n# to run in parallel. When set to 0 Doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of\n# subgraphs. When you want a differently looking font in the dot files that\n# Doxygen generates you can specify fontname, fontcolor and fontsize attributes.\n# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,\n# Edge and Graph Attributes specification</a> You need to make sure dot is able\n# to find the font, which can be done by putting it in a standard location or by\n# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the\n# directory containing the font. Default graphviz fontsize is 14.\n# The default value is: fontname=Helvetica,fontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_COMMON_ATTR        = \"fontname=Helvetica,fontsize=10\"\n\n# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can\n# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a\n# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about\n# arrows shapes.</a>\n# The default value is: labelfontname=Helvetica,labelfontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_EDGE_ATTR          = \"labelfontname=Helvetica,labelfontsize=10\"\n\n# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes\n# around nodes set 'shape=plain' or 'shape=plaintext' <a\n# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>\n# The default value is: shape=box,height=0.2,width=0.4.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NODE_ATTR          = \"shape=box,height=0.2,width=0.4\"\n\n# You can set the path where dot can find font specified with fontname in\n# DOT_COMMON_ATTR and others dot attributes.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then Doxygen will\n# generate a graph for each documented class showing the direct and indirect\n# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and\n# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case\n# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the\n# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.\n# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance\n# relations will be shown as texts / links. Explicit enabling an inheritance\n# graph or choosing a different representation for an inheritance graph of a\n# specific class, can be accomplished by means of the command \\inheritancegraph.\n# Disabling an inheritance graph can be accomplished by means of the command\n# \\hideinheritancegraph.\n# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.\n# The default value is: YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then Doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes. Explicit enabling a collaboration graph,\n# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the\n# command \\collaborationgraph. Disabling a collaboration graph can be\n# accomplished by means of the command \\hidecollaborationgraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then Doxygen will generate a graph for\n# groups, showing the direct groups dependencies. Explicit enabling a group\n# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means\n# of the command \\groupgraph. Disabling a directory graph can be accomplished by\n# means of the command \\hidegroupgraph. See also the chapter Grouping in the\n# manual.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, Doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = YES\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the DOT_UML_DETAILS tag is set to NO, Doxygen will show attributes and\n# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS\n# tag is set to YES, Doxygen will add type and arguments for attributes and\n# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, Doxygen\n# will not generate fields with class member information in the UML graphs. The\n# class diagrams will look similar to the default class diagrams but using UML\n# notation for the relationships.\n# Possible values are: NO, YES and NONE.\n# The default value is: NO.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nDOT_UML_DETAILS        = NO\n\n# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters\n# to display on a single line. If the actual line length exceeds this threshold\n# significantly it will be wrapped across multiple lines. Some heuristics are\n# applied to avoid ugly line breaks.\n# Minimum value: 0, maximum value: 1000, default value: 17.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_WRAP_THRESHOLD     = 17\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then Doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,\n# can be accomplished by means of the command \\includegraph. Disabling an\n# include graph can be accomplished by means of the command \\hideincludegraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then Doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set\n# to NO, can be accomplished by means of the command \\includedbygraph. Disabling\n# an included by graph can be accomplished by means of the command\n# \\hideincludedbygraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then Doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = YES\n\n# If the CALLER_GRAPH tag is set to YES then Doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = YES\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then Doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then Doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories. Explicit enabling a directory graph, when\n# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command\n# \\directorygraph. Disabling a directory graph can be accomplished by means of\n# the command \\hidedirectorygraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels\n# of child directories generated in directory dependency graphs by dot.\n# Minimum value: 1, maximum value: 25, default value: 1.\n# This tag requires that the tag DIRECTORY_GRAPH is set to YES.\n\nDIR_GRAPH_MAX_DEPTH    = 1\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# https://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# You can include diagrams made with dia in Doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using PlantUML, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file or to the filename of jar file\n# to be used. If left blank, it is assumed PlantUML is not used or called during\n# a preprocessing step. Doxygen will generate a warning when it encounters a\n# \\startuml command in this case and will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using PlantUML, the PLANTUML_CFG_FILE tag can be used to specify a\n# configuration file for PlantUML.\n\nPLANTUML_CFG_FILE      =\n\n# When using PlantUML, the specified paths are searched for files specified by\n# the !include statement in a PlantUML block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, Doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 60\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 5\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = YES\n\n# If the GENERATE_LEGEND tag is set to YES Doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# Note: This tag requires that UML_LOOK isn't set, i.e. the Doxygen internal\n# graphical representation for inheritance and collaboration diagrams is used.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, Doxygen will remove the intermediate\n# files that are used to generate the various graphs.\n#\n# Note: This setting is not only used for dot files but also for msc temporary\n# files.\n# The default value is: YES.\n\nDOT_CLEANUP            = YES\n\n# You can define message sequence charts within Doxygen comments using the \\msc\n# command. If the MSCGEN_TOOL tag is left empty (the default), then Doxygen will\n# use a built-in version of mscgen tool to produce the charts. Alternatively,\n# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,\n# specifying prog as the value, Doxygen will call the tool as prog -T\n# <outfile_format> -o <outputfile> <inputfile>. The external tool should support\n# output file formats \"png\", \"eps\", \"svg\", and \"ismap\".\n\nMSCGEN_TOOL            =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n"
  },
  {
    "path": "include/css-colors.h",
    "content": "#ifndef ROFI_INCLUDE_CSS_COLORS_H\n#define ROFI_INCLUDE_CSS_COLORS_H\n\n#include <stdint.h>\n/**\n * @defgroup CSSCOLORS CssColors\n * @ingroup HELPERS\n *\n * Lookup table for CSS 4.0 named colors. Like `Navo`.\n *\n * @{\n */\n\n/**\n * Structure of colors.\n */\ntypedef struct CSSColor {\n  /** CSS name of the color. */\n  char *name;\n  /** BGRA 8 bit color components. */\n  uint8_t b, g, r, a;\n} CSSColor;\n\n/**\n * Array with all the named colors. Of type #CSSColor, there are #num_CSSColors\n * items in this array.\n */\nextern const CSSColor CSSColors[];\n/**\n * Number of named colors.\n */\nextern const unsigned int num_CSSColors;\n/** @} */\n#endif // ROFI_INCLUDE_CSS_COLORS_H\n"
  },
  {
    "path": "include/display-internal.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_DISPLAY_INTERNAL_H\n#define ROFI_DISPLAY_INTERNAL_H\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"nkutils-bindings.h\"\n#include <glib.h>\n\nstruct _workarea;\nstruct _view_proxy;\n\ntypedef struct _display_proxy {\n  gboolean (*setup)(GMainLoop *main_loop, NkBindings *bindings);\n  gboolean (*late_setup)(void);\n  void (*early_cleanup)(void);\n  void (*cleanup)(void);\n  void (*dump_monitor_layout)(void);\n  void (*startup_notification)(RofiHelperExecuteContext *context,\n                               GSpawnChildSetupFunc *child_setup,\n                               gpointer *user_data);\n  int (*monitor_active)(struct _workarea *mon);\n\n  void (*set_input_focus)(guint window);\n  void (*revert_input_focus)(void);\n  void (*get_clipboard_data)(int type, ClipboardCb callback, void *user_data);\n  void (*set_fullscreen_mode)(void);\n\n  guint (*scale)(void);\n\n  const struct _view_proxy *(*view)(void);\n} display_proxy;\n\n#endif\n"
  },
  {
    "path": "include/display.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_DISPLAY_H\n#define ROFI_DISPLAY_H\n\n#include \"helper.h\"\n#include \"nkutils-bindings.h\"\n#include <glib.h>\n\n/**\n * Structure describing a workarea/monitor.\n */\ntypedef struct _workarea {\n  /** numeric monitor id. */\n  int monitor_id;\n  /** if monitor is set as primary monitor. */\n  int primary;\n  /** Horizontal location (in pixels) of the monitor. */\n  int x;\n  /** Vertical location  (in pixels) of the monitor. */\n  int y;\n  /** Width of the monitor. */\n  int w;\n  /** Height of the monitor */\n  int h;\n  int mw, mh;\n  /** Output name of the monitor, e.g. eDP1 or VGA-1 */\n  char *name;\n  /** Pointer to next monitor */\n  struct _workarea *next;\n} workarea;\n\nstruct _display_proxy;\n\n/* Implementations */\nextern struct _display_proxy *const xcb_proxy;\n#ifdef ENABLE_WAYLAND\nextern struct _display_proxy *const wayland_proxy;\n#endif\n\nvoid display_init(const struct _display_proxy *disp_in);\n\n/**\n * @param mon workarea to be filled in.\n *\n * Fills in #mon with the information about the monitor rofi should show on.\n *\n * @returns TRUE if monitor is found, FALSE if no monitor could be detected.\n */\nint monitor_active(workarea *mon);\n\n/**\n * @param main_loop The GMainLoop\n * @param bindings The bindings object\n *\n * Setup the display backend\n *\n * @returns Whether the setup succeeded or not\n */\ngboolean display_setup(GMainLoop *main_loop, NkBindings *bindings);\n\n/**\n * Do some late setup of the display backend\n *\n * @returns Whether the setup succeeded or not\n */\ngboolean display_late_setup(void);\n\n/**\n * Do some early cleanup, like unmapping the surface\n */\nvoid display_early_cleanup(void);\n\n/**\n * Cleanup any remaining display related stuff\n */\nvoid display_cleanup(void);\n\n/**\n * Dumps the display layout for -help output\n */\nvoid display_dump_monitor_layout(void);\n\n/**\n * @param context The startup notification context for the application to launch\n * @param child_setup A pointer to return the child setup function\n * @param user_data A pointer to return the child setup function user_data\n *\n * Provides the needed child setup function\n */\nvoid display_startup_notification(RofiHelperExecuteContext *context,\n                                  GSpawnChildSetupFunc *child_setup,\n                                  gpointer *user_data);\n\nvoid display_set_input_focus(guint w);\nvoid display_revert_input_focus(void);\n\nguint display_scale(void);\n\nenum clipboard_type {\n  CLIPBOARD_DEFAULT,\n  CLIPBOARD_PRIMARY,\n};\n\ntypedef void (* ClipboardCb)(char *clipboard_data, void *user_data);\nvoid display_get_clipboard_data(enum clipboard_type, ClipboardCb callback, void* user_data);\n\nvoid display_set_fullscreen_mode(void);\n\n#endif\n"
  },
  {
    "path": "include/helper-theme.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_HELPER_THEME_H\n#define ROFI_HELPER_THEME_H\n#include \"theme.h\"\n#include <pango/pango.h>\n/**\n * @defgroup HELPERS Helpers\n * @{\n */\n/**\n * @param th The RofiHighlightColorStyle\n * @param tokens Array of regexes used for matching\n * @param input The input string to find the matches on\n * @param retv The Attribute list to update with matches\n *\n * Creates a set of pango attributes highlighting the matches found in the input\n * string.\n *\n * @returns the updated retv list.\n */\nPangoAttrList *helper_token_match_get_pango_attr(RofiHighlightColorStyle th,\n                                                 rofi_int_matcher **tokens,\n                                                 const char *input,\n                                                 PangoAttrList *retv);\n\n/**\n * @param retv The Attribute list to update with matches\n * @param start The start to highlighting.\n * @param end The end point for the highlight\n * @param th The RofiHighlightColorStyle\n *\n * Creates a set of pango attributes highlighting the matches found in the input\n * style.\n *\n */\nvoid helper_token_match_set_pango_attr_on_style(PangoAttrList *retv, int start,\n                                                int end,\n                                                RofiHighlightColorStyle th);\n/**\n * @param pfd Pango font description to validate.\n * @param font The name of the font to check.\n *\n * @returns true if font is valid.\n */\ngboolean helper_validate_font(PangoFontDescription *pfd, const char *font);\n/** @} */\n#endif // ROFI_HELPER_THEME_H\n"
  },
  {
    "path": "include/helper.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_HELPER_H\n#define ROFI_HELPER_H\n#include \"rofi-types.h\"\n#include <cairo.h>\nG_BEGIN_DECLS\n\n/**\n * @defgroup HELPERS Helpers\n */\n/**\n * @defgroup HELPER Helper\n * @ingroup HELPERS\n *\n * @{\n */\n\n/**\n * @param string The input string.\n * @param output Pointer to 2 dimensional array with parsed string.\n * @param length Length of 2 dimensional array.\n * @param ...    Key, value parse. Replaces the string Key with value.\n *\n * Parses a string into arguments. While replacing keys with values.\n *\n * @returns TRUE when successful, FALSE when failed.\n */\nint helper_parse_setup(char *string, char ***output, int *length, ...);\n\n/**\n * @param input The input string.\n * @param case_sensitive Whether case is significant.\n *\n * Tokenize the string on spaces.\n *\n * @returns a newly allocated array of matching objects\n */\nrofi_int_matcher **helper_tokenize(const char *input, int case_sensitive);\n\n/**\n * @param tokens Array of regex objects\n *\n * Frees the array of matching objects.\n */\nvoid helper_tokenize_free(rofi_int_matcher **tokens);\n\n/**\n * @param key The key to search for\n * @param val Pointer to the string to set to the key value (if found)\n *\n * Parse command line argument 'key' to character.\n * This one supports character escaping.\n *\n * @returns TRUE if key was found and val was set.\n */\nint find_arg_char(const char *const key, char *val);\n\n/**\n * @param key The key to search for\n * @param val Pointer to the string to set to the key value (if found)\n *\n * Parse command line argument 'key' to unsigned int.\n *\n * @returns TRUE if key was found and val was set.\n */\nint find_arg_uint(const char *const key, unsigned int *val);\n\n/**\n * @param key The key to search for\n * @param val Pointer to the string to set to the key value (if found)\n *\n * Parse command line argument 'key' to int.\n *\n * @returns TRUE if key was found and val was set.\n */\nint find_arg_int(const char *const key, int *val);\n\n/**\n * @param key The key to search for\n * @param val Pointer to the string to set to the key value (if found)\n *\n * Parse command line argument 'key' to string.\n *\n * @returns TRUE if key was found and val was set.\n */\nint find_arg_str(const char *const key, char **val);\n\n/**\n * @param key The key to search for\n *\n * Parse all command line options 'key' to string vector.\n *\n * @returns str vector. user should free array.\n */\nconst char **find_arg_strv(const char *const key);\n/**\n * @param key The key to search for\n *\n * Check if key is passed as argument.\n *\n * @returns return position of string or -1 if not found.\n */\nint find_arg(const char *const key);\n\n/**\n * @param tokens  List of (input) tokens to match.\n * @param input   The entry to match against.\n *\n * Tokenized match, match tokens to line input.\n *\n * @returns TRUE when matches, FALSE otherwise\n */\nint helper_token_match(rofi_int_matcher *const *tokens, const char *input);\n/**\n * @param cmd The command to execute.\n *\n * Execute cmd using config.run_command and outputs the result (stdout) to the\n * opened file descriptor.\n *\n * @returns a valid file descriptor on success, or -1 on failure.\n */\nint execute_generator(const char *cmd) __attribute__((nonnull));\n\n/**\n * @param pidfile The pidfile to create.\n * @param kill_running Try killing running instance.\n *\n * returns file descriptor (or -1 when failed)\n */\nint create_pid_file(const char *pidfile, gboolean kill_running);\n\n/**\n * Remove pid file\n */\nvoid remove_pid_file(int fd);\n\n/**\n * Do some input validation, especially the first few could break things.\n * It is good to catch them beforehand.\n *\n * This functions exits the program with 1 when it finds an invalid\n * configuration.\n */\nint config_sanity_check(void);\n\n/**\n * @param arg string to parse.\n *\n * Parses a string into an character.\n *\n * @returns character.\n */\nchar helper_parse_char(const char *arg);\n\n/**\n * @param argc number of arguments.\n * @param argv Array of arguments.\n *\n * Set the application arguments.\n */\nvoid cmd_set_arguments(int argc, char **argv);\n\n/**\n * @param input The path to expand\n *\n * Expand path, both `~` and `~<user>`\n *\n * @returns path\n */\nchar *rofi_expand_path(const char *input);\n\n/**\n * @param needle The string to find match weight off\n * @param needlelen The length of the needle\n * @param haystack The string to match against\n * @param haystacklen The length of the haystack\n * @param case_sensitive Whether case is significant.\n *\n * UTF-8 aware levenshtein distance calculation\n *\n * @returns the levenshtein distance between needle and haystack\n */\nunsigned int levenshtein(const char *needle, const glong needlelen,\n                         const char *haystack, const glong haystacklen,\n                         const int case_sensitive);\n\n/**\n * @param data the unvalidated character array holding possible UTF-8 data\n * @param length the length of the data array\n *\n * Convert string to valid utf-8, replacing invalid parts with replacement\n * character.\n *\n * @returns the converted UTF-8 string\n */\nchar *rofi_force_utf8(const gchar *data, ssize_t length);\n\n/**\n * @param input the char array holding latin text\n * @param length the length of the data array\n *\n * Converts latin to UTF-8.\n *\n * @return the UTF-8 representation of data\n */\nchar *rofi_latin_to_utf8_strdup(const char *input, gssize length);\n\n/**\n * @param pattern   The user input to match against.\n * @param plen      Pattern length.\n * @param str       The input to match against pattern.\n * @param slen      Length of str.\n * @param case_sensitive Whether case is significant.\n *\n *  rofi_scorer_fuzzy_evaluate implements a global sequence alignment algorithm\n * to find the maximum accumulated score by aligning `pattern` to `str`. It\n * applies when `pattern` is a subsequence of `str`.\n *\n *  Scoring criteria\n *  - Prefer matches at the start of a word, or the start of subwords in\n * CamelCase/camelCase/camel123 words. See WORD_START_SCORE/CAMEL_SCORE.\n *  - Non-word characters matter. See NON_WORD_SCORE.\n *  - The first characters of words of `pattern` receive bonus because they\n * usually have more significance than the rest. See\n * PATTERN_START_MULTIPLIER/PATTERN_NON_START_MULTIPLIER.\n *  - Superfluous characters in `str` will reduce the score (gap penalty). See\n * GAP_SCORE.\n *  - Prefer early occurrence of the first character. See\n * LEADING_GAP_SCORE/GAP_SCORE.\n *\n *  The recurrence of the dynamic programming:\n *  dp[i][j]: maximum accumulated score by aligning pattern[0..i] to str[0..j]\n *  dp[0][j] = leading_gap_penalty(0, j) + score[j]\n *  dp[i][j] = max(dp[i-1][j-1] + CONSECUTIVE_SCORE, max(dp[i-1][k] +\n * gap_penalty(k+1, j) + score[j] : k < j))\n *\n *  The first dimension can be suppressed since we do not need a matching\n * scheme, which reduces the space complexity from O(N*M) to O(M)\n *\n * @returns the sorting weight.\n */\nint rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str,\n                               glong slen, const int case_sensitive);\n/*@}*/\n\n/**\n * @param a    UTF-8 string to compare\n * @param b    UTF-8 string to compare\n * @param n    Maximum number of characters to compare\n *\n * Compares the `G_NORMALIZE_ALL_COMPOSE` forms of the two strings.\n *\n * @returns less than, equal to, or greater than zero if the first `n`\n * characters (not bytes) of `a` are found, respectively, to be less than, to\n * match, or be greater than the first `n` characters (not bytes) of `b`.\n */\nint utf8_strncmp(const char *a, const char *b, size_t n)\n    __attribute__((nonnull(1, 2)));\n\n/**\n * The startup notification context of the application to launch\n */\ntypedef struct {\n  /** The name of the application */\n  const gchar *name;\n  /** The binary name of the application */\n  const gchar *binary;\n  /** The description of the launch */\n  const gchar *description;\n  /** The icon name of the application */\n  const gchar *icon;\n  /** The application id (desktop file with the .desktop suffix) */\n  const gchar *app_id;\n  /** The window manager class of the application */\n  const gchar *wmclass;\n  /** The command we run */\n  const gchar *command;\n} RofiHelperExecuteContext;\n\n/**\n * @param wd   The working directory.\n * @param args The arguments of the command to exec.\n * @param error_precmd Prefix to error message command.\n * @param error_cmd Error message command\n * @param context The startup notification context, if any\n *\n * Executes the command\n *\n * @returns TRUE when successful, FALSE when failed.\n */\ngboolean helper_execute(const char *wd, char **args, const char *error_precmd,\n                        const char *error_cmd,\n                        RofiHelperExecuteContext *context);\n\n/**\n * @param wd The work directory (optional)\n * @param cmd The cmd to execute\n * @param run_in_term Indicate if command should be run in a terminal\n * @param context The startup notification context, if any\n *\n * Execute command.\n * If needed members of context are NULL, they will be filled.\n *\n * @returns FALSE On failure, TRUE on success\n */\ngboolean helper_execute_command(const char *wd, const char *cmd,\n                                gboolean run_in_term,\n                                RofiHelperExecuteContext *context);\n\n/**\n * @param file The file path\n * @param height The wanted height\n * Gets a surface from an svg path\n *\n * @returns a cairo surface from an svg path\n */\ncairo_surface_t *cairo_image_surface_create_from_svg(const gchar *file,\n                                                     int height);\n\n/**\n * Ranges.\n */\n\n/**\n * @param input String to parse\n * @param list  List of ranges\n * @param length Length of list.\n *\n * ranges\n */\nvoid parse_ranges(char *input, rofi_range_pair **list, unsigned int *length);\n\n/**\n * @param input String to parse\n *\n * @returns String matching should be case sensitive or insensitive\n */\nint parse_case_sensitivity(const char *input);\n\n/**\n * @param format The format string used. See below for possible syntax.\n * @param string The selected entry.\n * @param selected_line The selected line index.\n * @param filter The entered filter.\n *\n * Function that outputs the selected line in the user-specified format.\n * Currently the following formats are supported:\n *   * i: Print the index (0-(N-1))\n *   * d: Print the index (1-N)\n *   * s: Print input string.\n *   * q: Print quoted input string.\n *   * f: Print the entered filter.\n *   * F: Print the entered filter, quoted\n *\n * This functions outputs the formatted string to stdout, appends a newline (\\n)\n * character and calls flush on the file descriptor.\n */\nvoid rofi_output_formatted_line(const char *format, const char *string,\n                                int selected_line, const char *filter);\n\n/**\n * @param string The string with elements to be replaced\n * @param ...    Set of {key}, value that will be replaced, terminated by  a\n * NULL\n *\n * Items {key} are replaced by the value if '{key}' is passed as key/value pair,\n * otherwise removed from string. If the {key} is in between []  all the text\n * between [] are removed if {key} is not found. Otherwise key is replaced and [\n * & ] removed.\n *\n * This allows for optional replacement, f.e.   '{ssh-client} [-t  {title}] -e\n * \"{cmd}\"' the '-t {title}' is only there if {title} is set.\n *\n * @returns a new string with the keys replaced.\n */\nchar *helper_string_replace_if_exists(char *string, ...);\n\n/**\n * @param file File name passed to option.\n * @param ext NULL terminated array of file extension passed to option.\n * @param parent_dir The file that was used to import this file, or NULL.\n *\n * Get the full path to the theme, trying to resolve it over the possible\n * locations.\n *\n * @returns path to theme or copy of filename if not found.\n */\nchar *helper_get_theme_path(const char *file, const char **ext,\n                            const char *parent_dir)\n    __attribute__((nonnull(1, 2)));\n\n/**\n * @param name The name of the element to find.\n * @param state The state of the element.\n * @param exact If the match should be exact, or parent can be included.\n *\n * Find the configuration element. If not exact, the closest specified element\n * is returned.\n *\n * @returns the ThemeWidget if found, otherwise NULL.\n */\nConfigEntry *rofi_config_find_widget(const char *name, const char *state,\n                                     gboolean exact);\n\n/**\n * @param widget The widget to find the property on.\n * @param type   The %PropertyType to find.\n * @param property The property to find.\n * @param exact  If the property should only be found on this widget, or on\n * parents if not found.\n *\n * Find the property on the widget. If not exact, the parents are searched\n * recursively until match is found.\n *\n * @returns the Property if found, otherwise NULL.\n */\nProperty *rofi_theme_find_property(ConfigEntry *widget, PropertyType type,\n                                   const char *property, gboolean exact);\n\n/**\n * @returns get a human readable string with the current matching method.\n */\nconst char *helper_get_matching_mode_str(void);\n/**\n * Switch to the next matching method.\n */\nvoid helper_select_next_matching_mode(void);\n/**\n * Switch to the previous matching method.\n */\nvoid helper_select_previous_matching_mode(void);\n\n/**\n * Method to indicate fallthrough. This will help\n * gcc/llvm warning/static code analysis.\n */\n#if __has_attribute(__fallthrough__)\n#define rofi_fallthrough __attribute__((__fallthrough__))\n#else\n#define rofi_fallthrough                                                       \\\n  do {                                                                         \\\n  } while (0) /* fallthrough */\n#endif\n\nG_END_DECLS\n\n/**@} */\n#endif // ROFI_HELPER_H\n"
  },
  {
    "path": "include/history.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_HISTORY_H\n#define ROFI_HISTORY_H\n\n/**\n * @defgroup HISTORY History\n * @ingroup HELPERS\n *\n * Implements a very simple history module that can be used by a #Mode.\n *\n * This uses the following options from the #config object:\n * * #Settings::disable_history\n * * #Settings::ignored_prefixes\n *\n * @{\n */\n\n/**\n * @param filename The filename of the history cache.\n * @param entry    The entry to add/increment\n *\n * Sets the entry in the history, if it exists its use-count is incremented.\n *\n */\nvoid history_set(const char *filename, const char *entry)\n    __attribute__((nonnull));\n\n/**\n * @param filename The filename of the history cache.\n * @param entry    The entry to remove\n *\n * Removes the entry from the history.\n */\nvoid history_remove(const char *filename, const char *entry)\n    __attribute__((nonnull));\n\n/**\n * @param filename The filename of the history cache.\n * @param length   The length of the returned list.\n *\n * Gets the entries in the list (in order of usage)\n * @returns a list of entries length long. (and NULL terminated).\n */\nchar **history_get_list(const char *filename, unsigned int *length)\n    __attribute__((nonnull));\n\n/**@}*/\n#endif // ROFI_HISTORY_H\n"
  },
  {
    "path": "include/input-codes.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2025 Leandro Vital <leavitals@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef INPUT_CODES_H\n#define INPUT_CODES_H\n\n// Define BTN_* codes if not defined by the system headers\n#ifndef BTN_LEFT\n#define BTN_LEFT    0x110\n#endif\n\n#ifndef BTN_RIGHT\n#define BTN_RIGHT   0x111\n#endif\n\n#ifndef BTN_MIDDLE\n#define BTN_MIDDLE  0x112\n#endif\n\n#endif // INPUT_CODES_H\n"
  },
  {
    "path": "include/keyb.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_KEYB_H\n#define ROFI_KEYB_H\n\n#include <glib.h>\n#include <nkutils-bindings.h>\n\n/**\n * @defgroup KEYB KeyboardBindings\n *\n * @{\n */\n\n/**\n * List of all scopes the mouse can interact on.\n */\ntypedef enum {\n  SCOPE_GLOBAL,\n  SCOPE_MOUSE_LISTVIEW,\n  SCOPE_MOUSE_LISTVIEW_ELEMENT,\n\n#define SCOPE_MIN_FIXED SCOPE_MOUSE_EDITBOX\n  SCOPE_MOUSE_EDITBOX,\n  SCOPE_MOUSE_SCROLLBAR,\n  SCOPE_MOUSE_MODE_SWITCHER,\n#define SCOPE_MAX_FIXED SCOPE_MOUSE_MODE_SWITCHER\n} BindingsScope;\n\n/**\n * List of all possible actions that can be triggered by a keybinding.\n */\ntypedef enum {\n  /** Paste from primary clipboard */\n  PASTE_PRIMARY = 1,\n  /** Paste from secondary clipboard */\n  PASTE_SECONDARY,\n  /** Copy to secondary clipboard */\n  COPY_SECONDARY,\n  /** Clear the entry box. */\n  CLEAR_LINE,\n  /** Move to front of text */\n  MOVE_FRONT,\n  /** Move to end of text */\n  MOVE_END,\n  /** Move on word back */\n  MOVE_WORD_BACK,\n  /** Move on word forward */\n  MOVE_WORD_FORWARD,\n  /** Move character back */\n  MOVE_CHAR_BACK,\n  /** Move character forward */\n  MOVE_CHAR_FORWARD,\n  /** Remove previous word */\n  REMOVE_WORD_BACK,\n  /** Remove next work */\n  REMOVE_WORD_FORWARD,\n  /** Remove next character */\n  REMOVE_CHAR_FORWARD,\n  /** Remove previous character */\n  REMOVE_CHAR_BACK,\n  /** Remove till EOL */\n  REMOVE_TO_EOL,\n  /** Remove till SOL */\n  REMOVE_TO_SOL,\n  /** Transpose chars */\n  TRANSPOSE_CHARS,\n  /** Accept the current selected entry */\n  ACCEPT_ENTRY,\n  ACCEPT_ALT,\n  ACCEPT_CUSTOM,\n  ACCEPT_CUSTOM_ALT,\n  MODE_NEXT,\n  MODE_COMPLETE,\n  MODE_PREVIOUS,\n  TOGGLE_CASE_SENSITIVITY,\n  DELETE_ENTRY,\n  ROW_LEFT,\n  ROW_RIGHT,\n  ROW_UP,\n  ROW_DOWN,\n  ROW_TAB,\n  ELEMENT_NEXT,\n  ELEMENT_PREV,\n  PAGE_PREV,\n  PAGE_NEXT,\n  ROW_FIRST,\n  ROW_LAST,\n  ROW_SELECT,\n  CANCEL,\n  CUSTOM_1,\n  CUSTOM_2,\n  CUSTOM_3,\n  CUSTOM_4,\n  CUSTOM_5,\n  CUSTOM_6,\n  CUSTOM_7,\n  CUSTOM_8,\n  CUSTOM_9,\n  CUSTOM_10,\n  CUSTOM_11,\n  CUSTOM_12,\n  CUSTOM_13,\n  CUSTOM_14,\n  CUSTOM_15,\n  CUSTOM_16,\n  CUSTOM_17,\n  CUSTOM_18,\n  CUSTOM_19,\n  SCREENSHOT,\n  CHANGE_ELLIPSIZE,\n  TOGGLE_SORT,\n  SELECT_ELEMENT_1,\n  SELECT_ELEMENT_2,\n  SELECT_ELEMENT_3,\n  SELECT_ELEMENT_4,\n  SELECT_ELEMENT_5,\n  SELECT_ELEMENT_6,\n  SELECT_ELEMENT_7,\n  SELECT_ELEMENT_8,\n  SELECT_ELEMENT_9,\n  SELECT_ELEMENT_10,\n  ENTRY_HISTORY_UP,\n  ENTRY_HISTORY_DOWN,\n  MATCHER_UP,\n  MATCHER_DOWN\n} KeyBindingAction;\n\n/**\n * Actions mouse can take on the ListView.\n */\ntypedef enum {\n  SCROLL_LEFT = 1,\n  SCROLL_RIGHT,\n  SCROLL_DOWN,\n  SCROLL_UP,\n} MouseBindingListviewAction;\n\n/**\n * Actions mouse can take on the ListView element.\n */\ntypedef enum {\n  SELECT_HOVERED_ENTRY = 1,\n  ACCEPT_HOVERED_ENTRY,\n  ACCEPT_HOVERED_CUSTOM,\n} MouseBindingListviewElementAction;\n\n/**\n * Default mouse actions.\n */\ntypedef enum {\n  MOUSE_CLICK_DOWN = 1,\n  MOUSE_CLICK_UP,\n  MOUSE_DCLICK_DOWN,\n  MOUSE_DCLICK_UP,\n} MouseBindingMouseDefaultAction;\n\n/**\n * Parse the keybindings.\n * This should be called after the setting system is initialized.\n */\ngboolean parse_keys_abe(NkBindings *bindings);\n\n/**\n * Setup the keybindings\n * This adds all the entries to the settings system.\n */\nvoid setup_abe(void);\n\n/**\n * List all available key bindings to the terminal.\n */\nvoid abe_list_all_bindings(gboolean is_term);\n/**\n * @param name Don't have the name.\n *\n * @returns id, or UINT32_MAX if not found.\n */\nguint key_binding_get_action_from_name(const char *name);\n/**@}*/\n#endif // ROFI_KEYB_H\n"
  },
  {
    "path": "include/mode-private.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_PRIVATE_H\n#define ROFI_MODE_PRIVATE_H\n#include \"mode.h\"\n#include <gmodule.h>\nG_BEGIN_DECLS\n\n/**\n * Indicator what type of mode this is.\n * For now it can be the classic switcher, or also implement a completer.\n */\ntypedef enum {\n  /** Mode type is not set */\n  MODE_TYPE_UNSET = 0x0,\n  /** A normal mode. */\n  MODE_TYPE_SWITCHER = 0x1,\n  /** A mode that can be used to completer */\n  MODE_TYPE_COMPLETER = 0x2,\n  /** DMenu mode. */\n  MODE_TYPE_DMENU = 0x4,\n} ModeType;\n\n/**\n * @param data Pointer to #Mode object.\n *\n * Mode free function.\n */\ntypedef void (*_mode_free)(Mode *data);\n\n/**\n * @param sw The #Mode pointer\n * @param selected_line The selected line\n * @param state The state to display [out]\n * @param attribute_list List of extra (pango) attribute to apply when\n * displaying. [out][null]\n * @param get_entry if it should only return the state\n *\n * Get the value for displaying.\n *\n * @return the string and state for displaying.\n */\ntypedef char *(*_mode_get_display_value)(const Mode *sw,\n                                         unsigned int selected_line, int *state,\n                                         GList **attribute_list, int get_entry);\n\n/**\n * @param sw The #Mode pointer\n * @param selected_line The selected line\n * @param height The height of the icon\n *\n * Obtains the icon if available\n *\n * @return Get the icon\n */\ntypedef cairo_surface_t *(*_mode_get_icon)(const Mode *sw,\n                                           unsigned int selected_line,\n                                           unsigned int height);\n\n/**\n * @param sw The #Mode pointer\n * @param selected_line The selected line\n *\n * Obtains the string to complete.\n *\n * @return Get the completion string\n */\ntypedef char *(*_mode_get_completion)(const Mode *sw,\n                                      unsigned int selected_line);\n\n/**\n * @param data The #Mode pointer\n * @param tokens  List of (input) tokens to match.\n * @param index   The current selected index.\n *\n * Function prototype for the matching algorithm.\n *\n * @returns 1 when it matches, 0 if not.\n */\ntypedef int (*_mode_token_match)(const Mode *data, rofi_int_matcher **tokens,\n                                 unsigned int index);\n\n/**\n * @param sw The #Mode pointer\n *\n * Initialize the mode.\n *\n * @returns TRUE is successful\n */\ntypedef int (*__mode_init)(Mode *sw);\n\n/**\n * @param sw The #Mode pointer\n *\n * Get the number of entries.\n *\n * @returns the number of entries\n */\ntypedef unsigned int (*__mode_get_num_entries)(const Mode *sw);\n\n/**\n * @param sw The #Mode pointer\n *\n * Destroy the current mode. Still ready to restart.\n *\n */\ntypedef void (*__mode_destroy)(Mode *sw);\n\n/**\n * @param sw The #Mode pointer\n * @param menu_retv The return value\n * @param input The input string\n * @param selected_line The selected line\n *\n * Handle the user accepting an entry.\n *\n * @returns the next action to take\n */\ntypedef ModeMode (*_mode_result)(Mode *sw, int menu_retv, char **input,\n                                 unsigned int selected_line);\n\n/**\n * @param sw The #Mode pointer\n * @param input The input string\n *\n * Preprocess the input for sorting.\n *\n * @returns Entry stripped from markup for sorting\n */\ntypedef char *(*_mode_preprocess_input)(Mode *sw, const char *input);\n\n/**\n * @param sw The #Mode pointer\n *\n * Message to show in the message bar.\n *\n * @returns the (valid pango markup) message to display.\n */\ntypedef char *(*_mode_get_message)(const Mode *sw);\n\n/**\n * Create a new instance of this mode.\n * Free (free) result after use, after using mode_destroy.\n *\n * @returns Instantiate a new instance of this mode.\n */\ntypedef Mode *(*_mode_create)(void);\n\n/**\n * @param sw The #Mode pointer\n * @param menu_retv The return value\n * @param input The input string\n * @param selected_line The selected line\n * @param path the path that was completed\n *\n * Handle the user accepting an entry in completion mode.\n *\n * @returns the next action to take\n */\ntypedef ModeMode (*_mode_completer_result)(Mode *sw, int menu_retv,\n                                           char **input,\n                                           unsigned int selected_line,\n                                           char **path);\n/**\n * Structure defining a switcher.\n * It consists of a name, callback and if enabled\n * a textbox for the sidebar-mode.\n */\nstruct rofi_mode {\n  /** Used for external plugins. */\n  unsigned int abi_version;\n  /** Name (max 31 char long) */\n  char *name;\n  char cfg_name_key[128];\n  char *display_name;\n\n  /**\n   * A switcher normally consists of the following parts:\n   */\n  /** Initialize the Mode */\n  __mode_init _init;\n  /** Destroy the switcher, e.g. free all its memory. */\n  __mode_destroy _destroy;\n  /** Get number of entries to display. (unfiltered). */\n  __mode_get_num_entries _get_num_entries;\n  /** Process the result of the user selection. */\n  _mode_result _result;\n  /** Token match. */\n  _mode_token_match _token_match;\n  /** Get the string to display for the entry. */\n  _mode_get_display_value _get_display_value;\n  /** Get the icon for the entry. */\n  _mode_get_icon _get_icon;\n  /** Get the 'completed' entry. */\n  _mode_get_completion _get_completion;\n\n  _mode_preprocess_input _preprocess_input;\n\n  _mode_get_message _get_message;\n\n  /** Pointer to private data. */\n  void *private_data;\n\n  /**\n   * Free SWitcher\n   * Only to be used when the switcher object itself is dynamic.\n   * And has data in `ed`\n   */\n  _mode_free free;\n\n  /**\n   * Create mode.\n   */\n  _mode_create _create;\n\n  /**\n   * If this mode is used as completer.\n   */\n  _mode_completer_result _completer_result;\n\n  /** Extra fields for script */\n  void *ed;\n\n  /** Module */\n  GModule *module;\n\n  /** Fallack icon.*/\n  uint32_t fallback_icon_fetch_uid;\n  uint32_t fallback_icon_not_found;\n\n  /** type */\n  ModeType type;\n};\nG_END_DECLS\n#endif // ROFI_MODE_PRIVATE_H\n"
  },
  {
    "path": "include/mode.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_H\n#define ROFI_MODE_H\n#include \"rofi-types.h\"\n#include <cairo.h>\n#include <gmodule.h>\nG_BEGIN_DECLS\n\n/** ABI version to check if loaded plugin is compatible. */\n#define ABI_VERSION 7u\n\n/**\n * @defgroup MODE Mode\n *\n * The 'object' that makes a mode in rofi.\n * @{\n */\n\n/**\n * Type of a mode.\n * Access should be done via mode_* functions.\n */\ntypedef struct rofi_mode Mode;\n\n/**\n * Enum used to sum the possible states of ROFI.\n */\ntypedef enum {\n  /** Exit. */\n  MODE_EXIT = 1000,\n  /** Skip to the next cycle-able dialog. */\n  NEXT_DIALOG = 1001,\n  /** Reload current DIALOG */\n  RELOAD_DIALOG = 1002,\n  /** Previous dialog */\n  PREVIOUS_DIALOG = 1003,\n  /** Reloads the dialog and unset user input */\n  RESET_DIALOG = 1004,\n} ModeMode;\n\n/**\n * State returned by the rofi window.\n */\ntypedef enum {\n  /** Entry is selected. */\n  MENU_OK = 0x00010000,\n  /** User canceled the operation. (e.g. pressed escape) */\n  MENU_CANCEL = 0x00020000,\n  /** User requested a mode switch */\n  MENU_NEXT = 0x00040000,\n  /** Custom (non-matched) input was entered. */\n  MENU_CUSTOM_INPUT = 0x00080000,\n  /** User wanted to delete entry from history. */\n  MENU_ENTRY_DELETE = 0x00100000,\n  /** User wants to jump to another switcher. */\n  MENU_QUICK_SWITCH = 0x00200000,\n  /** User wants to jump to custom command. */\n  MENU_CUSTOM_COMMAND = 0x00800000,\n  /** Go to the previous menu. */\n  MENU_PREVIOUS = 0x00400000,\n  /** Go to the complete. */\n  MENU_COMPLETE = 0x01000000,\n  /** Bindings specifics */\n  MENU_CUSTOM_ACTION = 0x10000000,\n  /** Mask */\n  MENU_LOWER_MASK = 0x0000FFFF\n} MenuReturn;\n\n/**\n * @param mode The mode to initialize\n *\n * Initialize mode\n *\n * @returns FALSE if there was a failure, TRUE if successful\n */\nint mode_init(Mode *mode);\n\n/**\n * @param mode The mode to destroy\n *\n * Destroy the mode\n */\nvoid mode_destroy(Mode *mode);\n\n/**\n * @param mode The mode to query\n *\n * Get the number of entries in the mode.\n *\n * @returns an unsigned int with the number of entries.\n */\nunsigned int mode_get_num_entries(const Mode *mode);\n\n/**\n * @param mode The mode to query\n * @param selected_line The entry to query\n * @param state The state of the entry [out]\n * @param attribute_list List of extra (pango) attribute to apply when\n * displaying. [out][null]\n * @param get_entry If the should be returned.\n *\n * Returns the string as it should be displayed for the entry and the state of\n * how it should be displayed.\n *\n * @returns allocated new string and state when get_entry is TRUE otherwise just\n * the state.\n */\nchar *mode_get_display_value(const Mode *mode, unsigned int selected_line,\n                             int *state, GList **attribute_list, int get_entry);\n\n/**\n * @param mode The mode to query\n * @param selected_line The entry to query\n * @param height The desired height of the icon.\n *\n * Returns the icon for the selected_line\n *\n * @returns allocated new cairo_surface_t if applicable\n */\ncairo_surface_t *mode_get_icon(Mode *mode, unsigned int selected_line,\n                               unsigned int height);\n\n/**\n * @param mode The mode to query\n * @param selected_line The entry to query\n *\n * Return a string that can be used for completion. It has should have no\n * markup.\n *\n * @returns allocated string.\n */\nchar *mode_get_completion(const Mode *mode, unsigned int selected_line);\n\n/**\n * @param mode The mode to query\n * @param menu_retv The menu return value.\n * @param input Pointer to the user input string. [in][out]\n * @param selected_line the line selected by the user.\n *\n * Acts on the user interaction.\n *\n * @returns the next #ModeMode.\n */\nModeMode mode_result(Mode *mode, int menu_retv, char **input,\n                     unsigned int selected_line);\n\n/**\n * @param mode The mode to query\n * @param tokens The set of tokens to match against\n * @param selected_line The index of the entry to match\n *\n * Match entry against the set of tokens.\n *\n * @returns TRUE if matches\n */\nint mode_token_match(const Mode *mode, rofi_int_matcher **tokens,\n                     unsigned int selected_line);\n\n/**\n * @param mode The mode to query\n *\n * Get the name of the mode.\n *\n * @returns the name of the mode.\n */\nconst char *mode_get_name(const Mode *mode);\n\n/**\n * @param mode The mode to query\n *\n * Free the resources allocated for this mode.\n */\nvoid mode_free(Mode **mode);\n\n/**\n * @param mode The mode to query\n *\n * Helper functions for mode.\n * Get the private data object.\n */\nvoid *mode_get_private_data(const Mode *mode);\n\n/**\n * @param mode The mode to query\n * @param pd   Pointer to private data to attach to the mode.\n *\n * Helper functions for mode.\n * Set the private data object.\n */\nvoid mode_set_private_data(Mode *mode, void *pd);\n\n/**\n * @param mode The mode to query\n *\n * Get the name of the mode as it should be presented to the user.\n *\n * @return the user visible name of the mode\n */\nconst char *mode_get_display_name(const Mode *mode);\n\n/**\n * @param mode The mode to query\n *\n * Should be called once for each mode. This adds the display-name configuration\n * option for the mode.\n */\nvoid mode_set_config(Mode *mode);\n\n/**\n * @param mode The mode to query\n * @param input The input to process\n *\n * This processes the input so it can be used for matching and sorting.\n * This includes removing pango markup.\n *\n * @returns a newly allocated string\n */\nchar *mode_preprocess_input(Mode *mode, const char *input);\n\n/**\n * @param mode The mode to query\n *\n * Query the mode for a user display.\n *\n * @return a new allocated (valid pango markup) message to display (user should\n * free).\n */\nchar *mode_get_message(const Mode *mode);\n\n/**\n * @param mode The mode to create an instance off.\n *\n * @returns a new instance of the mode.\n */\nMode *mode_create(const Mode *mode);\n\n/**\n * @param sw The mode to query\n * @param menu_retv The menu return value.\n * @param input Pointer to the user input string. [in][out]\n * @param selected_line the line selected by the user.\n * @param path get the path to the selected file. [out]\n *\n * Acts on the user interaction.\n *\n * @returns the next #ModeMode.\n */\nModeMode mode_completer_result(Mode *sw, int menu_retv, char **input,\n                               unsigned int selected_line, char **path);\n\n/**\n * @param sw The mode to query.\n *\n * Check if mode is a valid completer.\n *\n * @returns TRUE if mode can be used as completer.\n */\ngboolean mode_is_completer(const Mode *sw);\n\n/**\n * @param mode The mode to query\n *\n * @returns the modes ABI version.\n */\nint mode_get_abi_version(Mode *const mode);\n\n/**\n * @param mode The mode to query\n * @param mod The GModule used to load the mode\n *\n * Set GModule used to load this plugin, this is used to\n * unload it on shutdown.\n */\nvoid mode_plugin_set_module(Mode *mode, GModule *mod);\n/**\n * @param mode The mode to query\n *\n * @returns the GModule used to load this plugin. NULL if not a plugin.\n */\nGModule *mode_plugin_get_module(Mode *mode);\n/**@}*/\nG_END_DECLS\n#endif\n"
  },
  {
    "path": "include/modes/combi.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_COMBI_H\n#define ROFI_MODE_COMBI_H\n#include \"mode.h\"\n\n/**\n * @defgroup COBIMode Combi\n * @ingroup MODES\n *\n * Dialog that can combine multiple #Mode into one view.\n *\n * This mode uses the following options from the #config object:\n *  * #Settings::combi_modes\n *\n * It creates the following option:\n *  * Settings::display_combi\n *\n * @{\n */\n\n/** #Mode object representing the combi dialog. */\nextern Mode combi_mode;\n\n/**@}*/\n#endif // ROFI_MODE_COMBI_H\n"
  },
  {
    "path": "include/modes/dmenu.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_DMENU_H\n#define ROFI_MODE_DMENU_H\n\n/**\n * @defgroup DMENU DMenu\n * @ingroup MODES\n *\n *\n * @{\n */\n/**\n * dmenu dialog.\n *\n * @returns TRUE if script was successful.\n */\nint dmenu_mode_dialog(void);\n\n/**\n * Print dmenu mode commandline options to stdout, for use in help menu.\n */\nvoid print_dmenu_options(void);\n\n/**@}*/\n#endif // ROFI_MODE_DMENU_H\n"
  },
  {
    "path": "include/modes/dmenuscriptshared.h",
    "content": "#ifndef ROFI_MODES_DMENU_SCRIPT_SHARED_H\n#define ROFI_MODES_DMENU_SCRIPT_SHARED_H\n\n#include <glib.h>\n#include <mode.h>\n#include <stdint.h>\n\ntypedef struct {\n  /** Entry content. (visible part) */\n  char *entry;\n\n  /** Display */\n  char *display;\n\n  /** Icon name to display. */\n  char **icon_name;\n  /** Async icon fetch handler. */\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  /** Current fallback icon index being tried */\n  int icon_fallback_index;\n  /** Hidden meta keywords. */\n  char *meta;\n\n  /** info */\n  char *info;\n\n  /** non-selectable */\n  gboolean nonselectable;\n\n  /** permanent */\n  gboolean permanent;\n\n  /** urgent */\n  gboolean urgent;\n  /** active */\n  gboolean active;\n} DmenuScriptEntry;\n/**\n * @param sw Unused\n * @param entry The entry to update.\n * @param buffer The buffer to parse.\n * @param length The buffer length.\n *\n * Updates entry with the parsed values from buffer.\n */\nvoid dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw,\n                                    DmenuScriptEntry *entry, char *buffer,\n                                    size_t length);\n#endif // ROFI_MODES_DMENU_SCRIPT_SHARED_H\n"
  },
  {
    "path": "include/modes/drun.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_DRUN_H\n#define ROFI_MODE_DRUN_H\n\n#include \"mode.h\"\n\n/**\n * @defgroup DRUNMode DRun\n * @ingroup MODES\n * @{\n */\n#ifdef ENABLE_DRUN\n/** #Mode object representing the desktop menu run dialog. */\nextern Mode drun_mode;\n#endif // ENABLE_DRUN\n/**@}*/\n#endif // ROFI_MODE_DRUN_H\n"
  },
  {
    "path": "include/modes/filebrowser.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_FILE_BROWSER_H\n#define ROFI_MODE_FILE_BROWSER_H\n#include \"mode.h\"\n/**\n * @defgroup FileBrowserMode FileBrowser\n * @ingroup MODES\n *\n *\n * @{\n */\n/** #Mode object representing the run dialog. */\nextern Mode file_browser_mode;\n\n/**\n * Create a new filebrowser.\n * @returns a new filebrowser structure.\n */\nMode *create_new_file_browser(void);\n/**\n * @param sw Mode object.\n * @param mretv return value passed in.\n * @param input The user input string.\n * @param selected_line The user selected line.\n * @param path The full path as output.\n *\n * @returns the state the user selected.\n */\nModeMode file_browser_mode_completer(Mode *sw, int mretv, char **input,\n                                     unsigned int selected_line, char **path);\n/**@}*/\n#endif // ROFI_MODE_FILE_BROWSER_H\n"
  },
  {
    "path": "include/modes/help-keys.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_HELPKEYS_H\n#define ROFI_MODE_HELPKEYS_H\n\n#include \"mode.h\"\n/**\n * @defgroup HELPKEYSMode KeysHelp\n * @ingroup MODES\n *\n * Displays the different keybindings available in *rofi*\n *\n * @{\n */\n/**\n * #Mode object representing the help key mode view\n */\nextern Mode help_keys_mode;\n/**@}*/\n#endif // ROFI_MODE_HELPKEYS_H\n"
  },
  {
    "path": "include/modes/modes.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODES_MODES_H\n#define ROFI_MODES_MODES_H\n\n/**\n * @defgroup MODES Modes\n */\n/**\n * List of available modes.\n */\n\n#include \"modes/combi.h\"\n#include \"modes/dmenu.h\"\n#include \"modes/drun.h\"\n#include \"modes/filebrowser.h\"\n#include \"modes/recursivebrowser.h\"\n#include \"modes/help-keys.h\"\n#include \"modes/run.h\"\n#include \"modes/script.h\"\n#include \"modes/ssh.h\"\n#include \"modes/wayland-window.h\"\n#include \"modes/window.h\"\n#endif // ROFI_MODES_MODES_H\n"
  },
  {
    "path": "include/modes/recursivebrowser.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_RECURSIVE_BROWSER_H\n#define ROFI_MODE_RECURSIVE_BROWSER_H\n#include \"mode.h\"\n/**\n * @defgroup FileBrowserMode FileBrowser\n * @ingroup MODES\n *\n *\n * @{\n */\n/** #Mode object representing the run dialog. */\nextern Mode recursive_browser_mode;\n\n/**\n * Create a new filebrowser.\n * @returns a new filebrowser structure.\n */\nMode *create_new_recursive_browser(void);\n/**\n * @param sw Mode object.\n * @param mretv return value passed in.\n * @param input The user input string.\n * @param selected_line The user selected line.\n * @param path The full path as output.\n *\n * @returns the state the user selected.\n */\nModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,\n                                     unsigned int selected_line, char **path);\n/**@}*/\n#endif // ROFI_MODE_RECURSIVE_BROWSER_H\n"
  },
  {
    "path": "include/modes/run.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_RUN_H\n#define ROFI_MODE_RUN_H\n\n#include \"mode.h\"\n\n/**\n * @defgroup RUNMode Run\n * @ingroup MODES\n *\n * This mode uses the following options from the #config object:\n *  * #Settings::run_command\n *  * #Settings::run_shell_command\n *  * #Settings::run_list_command\n *\n * @{\n */\n/** #Mode object representing the run dialog. */\nextern Mode run_mode;\n\n/**@}*/\n#endif // ROFI_MODE_RUN_H\n"
  },
  {
    "path": "include/modes/script.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_SCRIPT_H\n#define ROFI_MODE_SCRIPT_H\n\n#include \"mode.h\"\n\n/**\n * @defgroup SCRIPTMode Script\n * @ingroup MODES\n *\n * @{\n */\n/**\n * @param str   The input string to parse\n *\n * Parse an argument string into the right ScriptOptions data object.\n * This is off format: \\<Name\\>:\\<Script\\>\n *\n * @returns NULL when it fails, a newly allocated ScriptOptions when successful.\n */\nMode *script_mode_parse_setup(const char *str);\n\n/**\n * @param token The modes str to check\n *\n * Check if token could be a valid script modes.\n *\n * @returns true when valid.\n */\ngboolean script_mode_is_valid(const char *token);\n\n/**\n * Gather the users scripts from `~/.config/rofi/scripts/`\n */\nvoid script_mode_gather_user_scripts(void);\n\n/**\n * Cleanup memory allocated by `script_mode_gather_user_scripts`\n */\nvoid script_mode_cleanup(void);\n/**\n * @param is_term if printed to terminal\n *\n * List the user scripts found.\n */\nvoid script_user_list(gboolean is_term);\n/**@}*/\n#endif // ROFI_MODE_SCRIPT_H\n"
  },
  {
    "path": "include/modes/ssh.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_SSH_H\n#define ROFI_MODE_SSH_H\n#include \"mode.h\"\n/**\n * @defgroup SSHMode SSH\n * @ingroup MODES\n *\n * SSH Mode, returns a list of known SSH hosts the user can log into.\n * It does this by parsing the SSH config file and optional the known host  and\n * host list It also keeps history of the last chosen hosts.\n *\n * This mode uses the following options from the #config object:\n *  * #Settings::ssh_command\n *  * #Settings::parse_known_hosts\n *  * #Settings::parse_hosts\n *\n * @{\n */\n\n/** #Mode object representing the ssh mode. */\nextern Mode ssh_mode;\n/**@}*/\n#endif // ROFI_MODE_SSH_H\n"
  },
  {
    "path": "include/modes/wayland-window.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2022 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_WAYLAND_WINDOW_H\n#define ROFI_MODE_WAYLAND_WINDOW_H\n\n#include \"mode.h\"\n\n/**\n * @defgroup WINDOWMode Window\n * @ingroup MODES\n *\n * @{\n */\n#if defined(WINDOW_MODE) && defined(ENABLE_WAYLAND)\n\nextern Mode wayland_window_mode;\n\n#endif\n/** @}*/\n#endif // ROFI_MODE_WAYLAND_WINDOW_H\n"
  },
  {
    "path": "include/modes/window.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MODE_WINDOW_H\n#define ROFI_MODE_WINDOW_H\n\n#include \"mode.h\"\n\n/**\n * @defgroup WINDOWMode Window\n * @ingroup MODES\n *\n * @{\n */\n#if defined(WINDOW_MODE) && defined(ENABLE_XCB)\n\nextern Mode window_mode;\nextern Mode window_mode_cd;\n\nvoid window_client_handle_signal(xcb_window_t win, gboolean create);\n#endif // defined(WINDOW_MODE) && defined(ENABLE_XCB)\n/** @}*/\n#endif // ROFI_MODE_WINDOW_H\n"
  },
  {
    "path": "include/rofi-icon-fetcher.h",
    "content": "#ifndef ROFI_ICON_FETCHER_H\n#define ROFI_ICON_FETCHER_H\n\n#include <cairo.h>\n#include <glib.h>\n#include <stdint.h>\n\n/**\n * @defgroup ICONFETCHER IconFetcher\n * @ingroup HELPERS\n *\n * Small helper of to fetch icons. This makes use of the 'view' threadpool.\n * @{\n */\n\n/**\n * Initialize the icon fetcher.\n */\nvoid rofi_icon_fetcher_init(void);\n\n/**\n * Destroy and free the memory used by the icon fetcher.\n */\nvoid rofi_icon_fetcher_destroy(void);\n\n/**\n * @param name The name of the icon to fetch.\n * @param size The size of the icon to fetch.\n *\n * Query the icon-theme for icon with name and size.\n * The returned icon will be the best match for the requested size, it should\n * still be resized to the actual size.\n *\n * name can also be a full path, if prefixed with file://.\n *\n * @returns the uid identifying the request.\n */\nuint32_t rofi_icon_fetcher_query(const char *name, const int size);\n\n/**\n * @param name The name of the icon to fetch.\n * @param wsize The width of the icon to fetch.\n * @param hsize The height of the icon to fetch.\n *\n * Query the icon-theme for icon with name and size.\n * The returned icon will be the best match for the requested size, it should\n * still be resized to the actual size. For icons it will take the min of wsize\n * and hsize.\n *\n * name can also be a full path, if prefixed with file://.\n *\n * @returns the uid identifying the request.\n */\nuint32_t rofi_icon_fetcher_query_advanced(const char *name, const int wsize,\n                                          const int hsize);\n\n/**\n * @param uid The unique id representing the matching request.\n *\n * If the surface is used, the user should reference the surface.\n *\n * @returns the surface with the icon, NULL when not found.\n */\ncairo_surface_t *rofi_icon_fetcher_get(const uint32_t uid);\n\n/**\n * @param uid The unique id representing the matching request.\n * @param surface [out] The surface found.\n *\n * If the surface is used, the user should reference the surface.\n *\n * @returns false if a query was done and failed.\n */\ngboolean rofi_icon_fetcher_get_ex(const uint32_t uid,\n                                  cairo_surface_t **surface);\n/**\n * @param path the image path to check.\n *\n * Checks if a file is a supported image. (by looking at extension).\n *\n * @returns true if image, false otherwise.\n */\ngboolean rofi_icon_fetcher_file_is_image(const char *const path);\n/** @} */\n#endif // ROFI_ICON_FETCHER_H\n"
  },
  {
    "path": "include/rofi-types.h",
    "content": "#ifndef INCLUDE_ROFI_TYPES_H\n#define INCLUDE_ROFI_TYPES_H\n#include <glib.h>\n#include <stdint.h>\nG_BEGIN_DECLS\n\n/**\n * Type of property\n */\ntypedef enum {\n  /** Integer */\n  P_INTEGER,\n  /** Double */\n  P_DOUBLE,\n  /** String */\n  P_STRING,\n  /** Boolean */\n  P_BOOLEAN,\n  /** Color */\n  P_COLOR,\n  /** Image */\n  P_IMAGE,\n  /** RofiPadding */\n  P_PADDING,\n  /** Link to global setting */\n  P_LINK,\n  /** Position */\n  P_POSITION,\n  /** Highlight */\n  P_HIGHLIGHT,\n  /** List */\n  P_LIST,\n  /** Orientation */\n  P_ORIENTATION,\n  /** Cursor */\n  P_CURSOR,\n  /** Inherit */\n  P_INHERIT,\n  /** Number of types. */\n  P_NUM_TYPES,\n} PropertyType;\n\n/**\n * This array maps PropertyType to a user-readable name.\n * It is important this is kept in sync.\n */\nextern const char *const PropertyTypeName[P_NUM_TYPES];\n\n/** Style of text highlight */\ntypedef enum {\n  /** no highlight */\n  ROFI_HL_NONE = 0,\n  /** bold */\n  ROFI_HL_BOLD = 1,\n  /** underline */\n  ROFI_HL_UNDERLINE = 2,\n  /** strikethrough */\n  ROFI_HL_STRIKETHROUGH = 16,\n  /** italic */\n  ROFI_HL_ITALIC = 4,\n  /** color */\n  ROFI_HL_COLOR = 8,\n  /** uppercase */\n  ROFI_HL_UPPERCASE = 32,\n  /** lowercase */\n  ROFI_HL_LOWERCASE = 64,\n  /** capitalize */\n  ROFI_HL_CAPITALIZE = 128\n} RofiHighlightStyle;\n\n/** Style of line */\ntypedef enum {\n  /** Solid line */\n  ROFI_HL_SOLID,\n  /** Dashed line */\n  ROFI_HL_DASH\n} RofiLineStyle;\n\n/**\n * Distance unit type.\n */\ntypedef enum {\n  /** PixelWidth in pixels. */\n  ROFI_PU_PX,\n  /** PixelWidth in millimeters. */\n  ROFI_PU_MM,\n  /** PixelWidth in EM. */\n  ROFI_PU_EM,\n  /** PixelWidget in percentage */\n  ROFI_PU_PERCENT,\n  /** PixelWidth in CH. */\n  ROFI_PU_CH,\n} RofiPixelUnit;\n\n/**\n * Structure representing a distance.\n */\ntypedef enum {\n  ROFI_DISTANCE_MODIFIER_NONE,\n  ROFI_DISTANCE_MODIFIER_ADD,\n  ROFI_DISTANCE_MODIFIER_SUBTRACT,\n  ROFI_DISTANCE_MODIFIER_DIVIDE,\n  ROFI_DISTANCE_MODIFIER_MULTIPLY,\n  ROFI_DISTANCE_MODIFIER_MODULO,\n  ROFI_DISTANCE_MODIFIER_GROUP,\n  ROFI_DISTANCE_MODIFIER_MIN,\n  ROFI_DISTANCE_MODIFIER_MAX,\n  ROFI_DISTANCE_MODIFIER_ROUND,\n  ROFI_DISTANCE_MODIFIER_FLOOR,\n  ROFI_DISTANCE_MODIFIER_CEIL,\n} RofiDistanceModifier;\n\ntypedef struct RofiDistanceUnit {\n  /** Distance */\n  double distance;\n  /** Unit type of the distance */\n  RofiPixelUnit type;\n\n  /** Type */\n  RofiDistanceModifier modtype;\n\n  /** Modifier */\n  struct RofiDistanceUnit *left;\n\n  /** Modifier */\n  struct RofiDistanceUnit *right;\n} RofiDistanceUnit;\n\ntypedef struct {\n  /** Base */\n  RofiDistanceUnit base;\n  /** Style of the line (optional)*/\n  RofiLineStyle style;\n} RofiDistance;\n\n/**\n * Type of orientation.\n */\ntypedef enum {\n  ROFI_ORIENTATION_VERTICAL,\n  ROFI_ORIENTATION_HORIZONTAL\n} RofiOrientation;\n\n/**\n * Cursor type.\n */\ntypedef enum {\n  ROFI_CURSOR_DEFAULT,\n  ROFI_CURSOR_POINTER,\n  ROFI_CURSOR_TEXT\n} RofiCursorType;\n\n/**\n * Represent the color in theme.\n */\ntypedef struct {\n  /** red channel */\n  double red;\n  /** green channel */\n  double green;\n  /** blue channel */\n  double blue;\n  /**  alpha channel */\n  double alpha;\n} ThemeColor;\n\n/**\n * Theme Image\n */\ntypedef enum { ROFI_IMAGE_URL, ROFI_IMAGE_LINEAR_GRADIENT } RofiImageType;\n\ntypedef enum {\n  ROFI_DIRECTION_LEFT,\n  ROFI_DIRECTION_RIGHT,\n  ROFI_DIRECTION_TOP,\n  ROFI_DIRECTION_BOTTOM,\n  ROFI_DIRECTION_ANGLE,\n} RofiDirection;\n\ntypedef enum {\n  ROFI_SCALE_NONE,\n  ROFI_SCALE_BOTH,\n  ROFI_SCALE_HEIGHT,\n  ROFI_SCALE_WIDTH,\n} RofiScaleType;\n\ntypedef struct {\n  RofiImageType type;\n  char *url;\n  RofiScaleType scaling;\n  int wsize;\n  int hsize;\n\n  RofiDirection dir;\n  double angle;\n  /** colors */\n  GList *colors;\n\n  /** cached image */\n  uint32_t surface_id;\n\n} RofiImage;\n\n/**\n * RofiPadding\n */\ntypedef struct {\n  RofiDistance top;\n  RofiDistance right;\n  RofiDistance bottom;\n  RofiDistance left;\n} RofiPadding;\n\n/**\n * Theme highlight.\n */\ntypedef struct {\n  /** style to display */\n  RofiHighlightStyle style;\n  /** Color */\n  ThemeColor color;\n} RofiHighlightColorStyle;\n\n/**\n * Enumeration indicating location or gravity of window.\n *\n * \\verbatim WL_NORTH_WEST      WL_NORTH      WL_NORTH_EAST \\endverbatim\n * \\verbatim WL_EAST            WL_CENTER     WL_EAST \\endverbatim\n * \\verbatim WL_SOUTH_WEST      WL_SOUTH      WL_SOUTH_EAST\\endverbatim\n *\n * @ingroup CONFIGURATION\n */\ntypedef enum {\n  /** Center */\n  WL_CENTER = 0,\n  /** Top middle */\n  WL_NORTH = 1,\n  /** Middle right */\n  WL_EAST = 2,\n  /** Bottom middle */\n  WL_SOUTH = 4,\n  /** Middle left */\n  WL_WEST = 8,\n  /** Left top corner. */\n  WL_NORTH_WEST = WL_NORTH | WL_WEST,\n  /** Top right */\n  WL_NORTH_EAST = WL_NORTH | WL_EAST,\n  /** Bottom right */\n  WL_SOUTH_EAST = WL_SOUTH | WL_EAST,\n  /** Bottom left */\n  WL_SOUTH_WEST = WL_SOUTH | WL_WEST,\n} WindowLocation;\n\ntypedef union _PropertyValue {\n  /** integer */\n  int i;\n  /** Double */\n  double f;\n  /** String */\n  char *s;\n  /** boolean */\n  gboolean b;\n  /** Color */\n  ThemeColor color;\n  /** RofiPadding */\n  RofiPadding padding;\n  /** Reference */\n  struct {\n    /** Name */\n    char *name;\n    /** Cached looked up ref */\n    struct Property *ref;\n    /** Property default */\n    struct Property *def_value;\n  } link;\n  /** Highlight Style */\n  RofiHighlightColorStyle highlight;\n  /** Image */\n  RofiImage image;\n  /** List */\n  GList *list;\n} PropertyValue;\n\n/**\n * Property structure.\n */\ntypedef struct Property {\n  /** Name of property */\n  char *name;\n  /** Type of property. */\n  PropertyType type;\n  /** Value */\n  PropertyValue value;\n} Property;\n\n/**\n * Describe the media constraint type.\n */\ntypedef enum {\n  /** Minimum width constraint. */\n  THEME_MEDIA_TYPE_MIN_WIDTH,\n  /** Maximum width constraint. */\n  THEME_MEDIA_TYPE_MAX_WIDTH,\n  /** Minimum height constraint. */\n  THEME_MEDIA_TYPE_MIN_HEIGHT,\n  /** Maximum height constraint. */\n  THEME_MEDIA_TYPE_MAX_HEIGHT,\n  /** Monitor id constraint. */\n  THEME_MEDIA_TYPE_MON_ID,\n  /** Minimum aspect ratio constraint. */\n  THEME_MEDIA_TYPE_MIN_ASPECT_RATIO,\n  /** Maximum aspect ratio constraint. */\n  THEME_MEDIA_TYPE_MAX_ASPECT_RATIO,\n  /** Boolean option for use with env. */\n  THEME_MEDIA_TYPE_BOOLEAN,\n  /** Invalid entry. */\n  THEME_MEDIA_TYPE_INVALID,\n} ThemeMediaType;\n\n/**\n * Theme Media description.\n */\ntypedef struct ThemeMedia {\n  ThemeMediaType type;\n  double value;\n  gboolean boolv;\n} ThemeMedia;\n\n/**\n * ThemeWidget.\n */\ntypedef struct ThemeWidget {\n  int set;\n  char *name;\n\n  unsigned int num_widgets;\n  struct ThemeWidget **widgets;\n\n  ThemeMedia *media;\n\n  GHashTable *properties;\n\n  struct ThemeWidget *parent;\n} ThemeWidget;\n\ntypedef ThemeWidget ConfigEntry;\n/**\n * Structure to hold a range.\n */\ntypedef struct rofi_range_pair {\n  int start;\n  int stop;\n} rofi_range_pair;\n\n/**\n * Internal structure for matching.\n */\ntypedef struct rofi_int_matcher_t {\n  GRegex *regex;\n  gboolean invert;\n} rofi_int_matcher;\n\n/**\n * Structure with data to process by each worker thread.\n * TODO: Make this more generic wrapper.\n */\ntypedef struct _thread_state {\n  void (*callback)(struct _thread_state *t, gpointer data);\n  void (*free)(void *);\n  int priority;\n} thread_state;\n\nextern GThreadPool *tpool;\n\nG_END_DECLS\n#endif // INCLUDE_ROFI_TYPES_H\n"
  },
  {
    "path": "include/rofi.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_MAIN_H\n#define ROFI_MAIN_H\n#include \"keyb.h\"\n#include \"mode.h\"\n#include \"rofi-types.h\"\n#include \"view.h\"\n#include <glib.h>\n#include <stdlib.h>\n#include <string.h>\n#include <xkbcommon/xkbcommon.h>\n\n/**\n * @defgroup Main Main\n * @{\n */\n\n/**\n * Pointer to xdg cache directory.\n */\nextern const char *cache_dir;\n\n/**\n * Get the number of enabled modes.\n *\n * @returns the number of enabled modes.\n */\nunsigned int rofi_get_num_enabled_modes(void);\n\n/**\n * @param index The mode to return. (should be smaller then\n * rofi_get_num_enabled_mode)\n *\n * Get an enabled mode handle.\n *\n * @returns a Mode handle.\n */\nconst Mode *rofi_get_mode(unsigned int index);\n\n/**\n * @param name Name of the mode to lookup.\n *\n * Find the index of the mode with name.\n *\n * @returns index of the mode in modes, -1 if not found.\n */\nint mode_lookup(const char *name);\n\n/**\n * @param str A GString with an error message to display.\n *\n * Queue an error.\n */\nvoid rofi_add_error_message(GString *str);\n\n/**\n * Clear the list of stored error messages.\n */\nvoid rofi_clear_error_messages(void);\n\n/**\n * @param str A GString with an warning message to display.\n *\n * Queue an warning.\n */\nvoid rofi_add_warning_message(GString *str);\n\n/**\n * Clear the list of stored warning messages.\n */\nvoid rofi_clear_warning_messages(void);\n/**\n * @param code the code to return\n *\n * Return value are used for integrating dmenu rofi in scripts.\n * This function sets the code that rofi will return on exit.\n */\nvoid rofi_set_return_code(int code);\n\nvoid rofi_quit_main_loop(void);\n\n/**\n * @param name Search for mode with this name.\n *\n * @return returns Mode * when found, NULL if not.\n */\nMode *rofi_collect_modes_search(const char *name);\n\n/**\n * Query the configure file completer.\n *\n * @returns the Mode that can be used for file completion or NULL when not\n * found.\n */\nconst Mode *rofi_get_completer(void);\n/** Reset terminal */\n#define color_reset \"\\033[0m\"\n/** Set terminal text bold */\n#define color_bold \"\\033[1m\"\n/** Set terminal text italic */\n#define color_italic \"\\033[2m\"\n/** Set terminal foreground text green */\n#define color_green \"\\033[0;32m\"\n/** Set terminal foreground text red */\n#define color_red \"\\033[0;31m\"\n\n/** Appends instructions on how to report an error. */\n#define ERROR_MSG(a)                                                           \\\n  a \"\\n\"                                                                       \\\n    \"If you suspect this is caused by a bug in rofi,\\n\"                        \\\n    \"please report the following information to rofi's github page:\\n\"         \\\n    \" * The generated commandline output when the error occurred.\\n\"           \\\n    \" * Output of -dump-xresource\\n\"                                           \\\n    \" * Steps to reproduce\\n\"                                                  \\\n    \" * The version of rofi you are running\\n\\n\"                               \\\n    \" <i>https://github.com/davatorium/rofi/</i>\"\n/** Indicates if ERROR_MSG uses pango markup */\n#define ERROR_MSG_MARKUP TRUE\n/**@}*/\n#endif\n"
  },
  {
    "path": "include/settings.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_SETTINGS_H\n#define ROFI_SETTINGS_H\n\n#include <glib.h>\n\n/**\n * Enumeration indicating the matching method to use.\n *\n * @ingroup CONFIGURATION\n */\ntypedef enum {\n  MM_NORMAL = 0,\n  MM_REGEX = 1,\n  MM_GLOB = 2,\n  MM_FUZZY = 3,\n  MM_PREFIX = 4,\n  MM_NUM_MATCHERS = 5\n} MatchingMethod;\n\n/**\n * Possible sorting methods for listview.\n */\ntypedef enum { SORT_NORMAL = 0, SORT_FZF = 1 } SortingMethod;\n\ntypedef enum {\n  DISPLAY_XCB,\n  DISPLAY_WAYLAND,\n} DisplayBackend;\n\n/**\n * Settings structure holding all (static) configurable options.\n * @ingroup CONFIGURATION\n */\ntypedef struct {\n  /** List of enabled modes */\n  char *modes;\n  /** Font string (pango format) */\n  char *menu_font;\n\n  /** Whether to load and show icons  */\n  gboolean show_icons;\n  \n  /** Custom command to generate preview icons */\n  char *preview_cmd;\n\n  /** Custom command to call when menu selection changes */\n  char *on_selection_changed;\n  /** Custom command to call when menu mode changes */\n  char *on_mode_changed;\n  /** Custom command to call when menu entry is accepted */\n  char *on_entry_accepted;\n  /** Custom command to call when menu is canceled */\n  char *on_menu_canceled;\n  /** Custom command to call when menu finds errors */\n  char *on_menu_error;\n  /** Custom command to call when menu screenshot is taken */\n  char *on_screenshot_taken;\n  /** Terminal to use  */\n  char *terminal_emulator;\n  /** SSH client to use */\n  char *ssh_client;\n  /** Command to execute when ssh session is selected */\n  char *ssh_command;\n  /** Command for executing an application */\n  char *run_command;\n  /** Command for executing an application in a terminal */\n  char *run_shell_command;\n  /** Command for listing executables */\n  char *run_list_command;\n  /** Command for window */\n  char *window_command;\n  /** Window fields to match in window mode */\n  char *window_match_fields;\n  /** Theme for icons */\n  char *icon_theme;\n\n  /** Backend */\n  DisplayBackend backend;\n\n  /** Wayland layer */\n  char *wayland_layer;\n  /** Windows location/gravity */\n  WindowLocation location;\n  /** Y offset */\n  int y_offset;\n  /** X offset */\n  int x_offset;\n  /** Always should config.menu_lines lines, even if less lines are available */\n  unsigned int fixed_num_lines;\n  /** Do not use history */\n  unsigned int disable_history;\n  /** Programs ignored for history */\n  char *ignored_prefixes;\n  /** Toggle to enable sorting. */\n  unsigned int sort;\n  /** Sorting method. */\n  SortingMethod sorting_method_enum;\n  /** Sorting method. */\n  char *sorting_method;\n\n  /** Desktop entries to match in drun */\n  char *drun_match_fields;\n  /** Only show entries in this category */\n  char *drun_categories;\n  /** Exclude entries in this category */\n  char *drun_exclude_categories;\n  /** Desktop entry show actions */\n  unsigned int drun_show_actions;\n  /** Desktop format display */\n  char *drun_display_format;\n  /** Desktop Link launch command */\n  char *drun_url_launcher;\n\n  /** Search case sensitivity */\n  unsigned int case_sensitive;\n  /** Smart case sensitivity like vim */\n  unsigned int case_smart;\n  /** Cycle through in the element list */\n  unsigned int cycle;\n  /** Height of an element in number of rows */\n  int element_height;\n  /** Sidebar mode, show the modes */\n  unsigned int sidebar_mode;\n  /** Mouse hover automatically selects */\n  gboolean hover_select;\n  /** Lazy filter limit. */\n  unsigned int lazy_filter_limit;\n  /** Auto select. */\n  unsigned int auto_select;\n  /** Hosts file parsing */\n  unsigned int parse_hosts;\n  /** Knonw_hosts file parsing */\n  unsigned int parse_known_hosts;\n  /** Combi Modes */\n  char *combi_modes;\n  char *matching;\n  MatchingMethod matching_method;\n  unsigned int tokenize;\n  /** Monitors */\n  char *monitor;\n  /** filter */\n  char *filter;\n  /** dpi */\n  int dpi;\n  /** Number threads (1 to disable) */\n  unsigned int threads;\n  unsigned int scroll_method;\n\n  char *window_format;\n  /** Click outside the window to exit */\n  int click_to_exit;\n\n  /** Try to take over compositor's global bindings (on Wayland) */\n  gboolean global_kb;\n\n  char *theme;\n  /** Path where plugins can be found. */\n  char *plugin_path;\n\n  /** Maximum history length per mode. */\n  unsigned int max_history_size;\n  gboolean combi_hide_mode_prefix;\n  /** Combi format display */\n  char *combi_display_format;\n\n  char matching_negate_char;\n\n  /** Cache directory. */\n  char *cache_dir;\n\n  /** Window Thumbnails */\n  gboolean window_thumbnail;\n\n  /** drun cache */\n  gboolean drun_use_desktop_cache;\n  gboolean drun_reload_desktop_cache;\n\n  /** Benchmark */\n  gboolean benchmark_ui;\n\n  gboolean normalize_match;\n  /** Steal focus */\n  gboolean steal_focus;\n  /** fallback icon */\n  char *application_fallback_icon;\n\n  /** refilter timeout limit, when more then these entries,go into timeout mode.\n   */\n  unsigned int refilter_timeout_limit;\n\n  /** workaround for broken xserver (#300 on xserver, #611) */\n  gboolean xserver_i300_workaround;\n  /** completer mode */\n  char *completer_mode;\n  /** Whether to enable imdkit, see #2123 */\n  gboolean enable_imdkit;\n} Settings;\n\n/** Default number of lines in the list view */\n#define DEFAULT_MENU_LINES 15\n/** Default number of columns in the list view */\n#define DEFAULT_MENU_COLUMNS 1\n/** Default window width */\n#define DEFAULT_MENU_WIDTH 50.0f\n\n/** Global Settings structure. */\nextern Settings config;\n#endif // ROFI_SETTINGS_H\n"
  },
  {
    "path": "include/theme.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef THEME_H\n#define THEME_H\n#include \"rofi-types.h\"\n#include <cairo.h>\n#include <glib.h>\n#include <widgets/widget.h>\n\n/**\n * Global pointer to the current active theme.\n */\nextern ThemeWidget *rofi_theme;\n\n/**\n * Used to store config options.\n */\nextern ThemeWidget *rofi_configuration;\n\n/**\n * @param base Handle to the current level in the theme.\n * @param name Name of the new element.\n *\n * Create a new element in the theme structure.\n *\n * @returns handle to the new entry.\n */\nThemeWidget *rofi_theme_find_or_create_name(ThemeWidget *base,\n                                            const char *name);\n\n/**\n * @param widget The widget handle.\n *\n * Print out the widget to the commandline.\n */\nvoid rofi_theme_print(ThemeWidget *widget);\n\n/**\n * @param widget The widget handle.\n * @param index The indenting index.\n *\n * Print out the widget to the commandline indented by index.\n */\nvoid rofi_theme_print_index(ThemeWidget *widget, int index);\n\n/**\n * @param type The type of the property to create.\n *\n * Create a theme property of type.\n *\n * @returns a new property.\n */\nProperty *rofi_theme_property_create(PropertyType type);\n\n/**\n * @param p The property to free.\n *\n * Free the content of the property.\n */\nvoid rofi_theme_property_free(Property *p);\n\n/**\n * @param p The property to free.\n * @param data User data (unused)\n *\n * Make a newly allocted copy of the property.\n *\n * @returns a copy of p\n */\nProperty *rofi_theme_property_copy(const Property *p, G_GNUC_UNUSED void *);\n/**\n * @param widget\n *\n * Free the widget and alll children.\n */\nvoid rofi_theme_free(ThemeWidget *widget);\n\n/**\n * @param file filename to parse.\n *\n * Parse the input theme file.\n *\n * @returns returns TRUE when error.\n */\ngboolean rofi_theme_parse_file(const char *file);\n\n/**\n * @param string to parse.\n *\n * Parse the input string in addition to theme file.\n *\n * @returns returns TRUE when error.\n */\ngboolean rofi_theme_parse_string(const char *string);\n\n/**\n * @param widget The widget handle.\n * @param table HashTable containing properties set.\n *\n * Merge properties with widgets current property.\n */\nvoid rofi_theme_widget_add_properties(ThemeWidget *widget, GHashTable *table);\n\n/**\n * Public API\n */\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the distance of the widget.\n *\n * @returns The distance value of this property for this widget.\n */\nRofiDistance rofi_theme_get_distance(const widget *widget, const char *property,\n                                     int def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the integer of the widget.\n *\n * @returns The integer value of this property for this widget.\n */\nint rofi_theme_get_integer(const widget *widget, const char *property, int def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the position of the widget.\n *\n * @returns The position value of this property for this widget.\n */\nint rofi_theme_get_position(const widget *widget, const char *property,\n                            int def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the boolean of the widget.\n *\n * @returns The boolean value of this property for this widget.\n */\nint rofi_theme_get_boolean(const widget *widget, const char *property, int def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the orientation indicated by %property of the widget.\n *\n * @returns The orientation of this property for this widget or %def not found.\n */\nRofiOrientation rofi_theme_get_orientation(const widget *widget,\n                                           const char *property,\n                                           RofiOrientation def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the cursor indicated by %property of the widget.\n *\n * @returns The cursor for this widget or %def if not found.\n */\nRofiCursorType rofi_theme_get_cursor_type(const widget *widget,\n                                          const char *property,\n                                          RofiCursorType def);\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the string of the widget.\n *\n * @returns The string value of this property for this widget.\n */\nconst char *rofi_theme_get_string(const widget *widget, const char *property,\n                                  const char *def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param def      The default value.\n *\n * Obtain the double of the widget.\n *\n * @returns The double value of this property for this widget.\n */\ndouble rofi_theme_get_double(const widget *widget, const char *property,\n                             double def);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param d        The drawable to apply color.\n *\n * Obtain the color of the widget and applies this to the drawable d.\n *\n */\nvoid rofi_theme_get_color(const widget *widget, const char *property,\n                          cairo_t *d);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param d        The drawable to apply color.\n *\n * Obtain the image of the widget and applies this to the drawable d.\n *\n * @return true if image is set.\n */\ngboolean rofi_theme_get_image(const widget *widget, const char *property,\n                              cairo_t *d);\n\n/**\n * @param widget   The widget to query\n * @param type  The type to check\n * @param property The property to query.\n *\n * Check if a rofi theme has a property set.\n *\n */\ngboolean rofi_theme_has_property(const widget *widget, const PropertyType type,\n                                 const char *property);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param pad      The default value.\n *\n * Obtain the padding of the widget.\n *\n * @returns The padding of this property for this widget.\n */\nRofiPadding rofi_theme_get_padding(const widget *widget, const char *property,\n                                   RofiPadding pad);\n\n/**\n * @param widget   The widget to query\n * @param property The property to query.\n * @param th The default value.\n *\n * Obtain the highlight .\n *\n * @returns The highlight of this property for this widget.\n */\nRofiHighlightColorStyle rofi_theme_get_highlight(widget *widget,\n                                                 const char *property,\n                                                 RofiHighlightColorStyle th);\n\n/**\n * @param d The distance handle.\n * @param ori The orientation.\n *\n * Convert RofiDistance into pixels.\n * @returns the number of pixels this distance represents.\n */\nint distance_get_pixel(RofiDistance d, RofiOrientation ori);\n/**\n * @param d The distance handle.\n * @param draw The cairo drawable.\n *\n * Set linestyle.\n */\nvoid distance_get_linestyle(RofiDistance d, cairo_t *draw);\n\n/**\n * Low-level functions.\n * These can be used by non-widgets to obtain values.\n */\n/**\n * @param name The name of the element to find.\n * @param state The state of the element.\n * @param exact If the match should be exact, or parent can be included.\n *\n * Find the theme element. If not exact, the closest specified element is\n * returned.\n *\n * @returns the ThemeWidget if found, otherwise NULL.\n */\nThemeWidget *rofi_theme_find_widget(const char *name, const char *state,\n                                    gboolean exact);\n\n/**\n * Reset the current theme.\n */\nvoid rofi_theme_reset(void);\n\n/**\n * @param file File name to prepare.\n *\n * Tries to find full path relative to parent file.\n *\n * @returns full path to file.\n */\nchar *rofi_theme_parse_prepare_file(const char *file);\n\n/**\n * Process conditionals.\n */\nvoid rofi_theme_parse_process_conditionals(void);\n\n/**\n * Process links.\n */\nvoid rofi_theme_parse_process_links(void);\n\n/**\n * @param parent target theme tree\n * @param child source theme three\n *\n * Merge all the settings from child into parent.\n */\nvoid rofi_theme_parse_merge_widgets(ThemeWidget *parent, ThemeWidget *child);\n\n/**\n * @param type the media type to parse.\n *\n * Returns the media type described by type.\n */\nThemeMediaType rofi_theme_parse_media_type(const char *type);\n\n/**\n * @param distance The distance object to copy.\n *\n * @returns a copy of the distance.\n */\nRofiDistance rofi_theme_property_copy_distance(RofiDistance const distance);\n\n/**\n * @param filename The file to validate.\n *\n * @returns the program exit code.\n */\nint rofi_theme_rasi_validate(const char *filename);\n\n/**\n *\n * Free memory.\n */\nvoid rofi_theme_free_parsed_files(void);\n\n/**\n * @param is_term Indicate if printed to terminal.\n *\n * Print the list of parsed config files.\n */\nvoid rofi_theme_print_parsed_files(int is_term);\n\n/**\n * @param widget The widget handle.\n * @param property The property to query.\n *\n * Returns a list of allocated RofiDistance objects that should be\n * freed.\n *\n * @returns a GList of  RofiDistance objects.\n */\nGList *rofi_theme_get_list_distance(const widget *widget, const char *property);\n\n/**\n * @param widget The widget handle.\n * @param property The property to query.\n *\n * Returns a list of allocated strings othat should be\n * freed.\n *\n * @returns a GList of strings.\n */\nGList *rofi_theme_get_list_strings(const widget *widget, const char *property);\n\n/**\n * Display scale function type\n */\ntypedef guint (*disp_scale_func)(void);\n\n/**\n * @param func The function pointer to scale getter.\n *\n * Dependency injection for changing display scale without theme library\n * depending on the display library\n */\nvoid rofi_theme_set_disp_scale_func(disp_scale_func func);\n#endif\n"
  },
  {
    "path": "include/timings.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/**\n * @defgroup TIMINGS Timings\n * @ingroup HELPERS\n * @{\n */\n#ifndef ROFI_TIMINGS_H\n#define ROFI_TIMINGS_H\n\n/**\n * Init the timestamping mechanism .\n * implementation.\n */\nvoid rofi_timings_init(void);\n/**\n * @param file filename tick originates from\n * @param str function name.\n * @param line line number\n * @param msg message\n *\n * Report a tick.\n */\nvoid rofi_timings_tick(const char *file, char const *str, int line,\n                       char const *msg);\n/**\n * Stop the timestamping mechanism\n */\nvoid rofi_timings_quit(void);\n\n/**\n * Start timestamping mechanism.\n * Call to this function is time 0.\n */\n#define TIMINGS_START() rofi_timings_init()\n/**\n * Report current time since TIMINGS_START\n */\n#define TICK() rofi_timings_tick(__FILE__, __func__, __LINE__, \"\")\n/**\n * @param a an string\n * Report current time since TIMINGS_START\n */\n#define TICK_N(a) rofi_timings_tick(__FILE__, __func__, __LINE__, a)\n/**\n * Stop timestamping mechanism.\n */\n#define TIMINGS_STOP() rofi_timings_quit()\n\n#else\n\n/**\n * Start timestamping mechanism.\n * Call to this function is time 0.\n */\n#define TIMINGS_START()\n/**\n * Stop timestamping mechanism.\n */\n#define TIMINGS_STOP()\n/**\n * Report current time since TIMINGS_START\n */\n#define TICK()\n/**\n * @param a an string\n * Report current time since TIMINGS_START\n */\n#define TICK_N(a)\n\n#endif // ROFI_TIMINGS_H\n/**@}*/\n"
  },
  {
    "path": "include/view-internal.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_VIEW_INTERNAL_H\n#define ROFI_VIEW_INTERNAL_H\n#include \"display.h\"\n#include \"keyb.h\"\n#include \"mode.h\"\n#include \"theme.h\"\n#include \"view.h\"\n#include \"widgets/box.h\"\n#include \"widgets/container.h\"\n#include \"widgets/icon.h\"\n#include \"widgets/listview.h\"\n#include \"widgets/textbox.h\"\n#include \"widgets/widget.h\"\n\n#ifdef ENABLE_XCB\n#include \"xcb.h\"\n#else\n#include \"xcb-dummy.h\"\n#endif\n\n#ifdef ENABLE_WAYLAND\n#include \"wayland.h\"\n#endif\n\n/**\n * @ingroup ViewHandle\n *\n * @{\n */\n// State of the menu.\n\nstruct RofiViewState {\n  /** #Mode bound to to this view. */\n  Mode *sw;\n\n  /** Flag indicating if view needs to be refiltered. */\n  int refilter;\n  /** Widget representing the main container. */\n  box *main_window;\n  /** #textbox showing the prompt in the input bar. */\n  textbox *prompt;\n  /** #textbox with the user input in the input bar. */\n  textbox *text;\n  /** #textbox showing the state of the case sensitive and sortng. */\n  textbox *case_indicator;\n\n  /** #listview holding the displayed elements. */\n  listview *list_view;\n  /** #textbox widget showing the overlay. */\n  textbox *overlay;\n  /** #container holding the message box */\n  container *mesg_box;\n  /** #textbox containing the message entry */\n  textbox *mesg_tb;\n\n  /** Array with the levenshtein distance for each element. */\n  int *distance;\n  /** Array with the translation between the filtered and unfiltered list. */\n  unsigned int *line_map;\n  /** number of (unfiltered) elements to show. */\n  unsigned int num_lines;\n\n  /** number of (filtered) elements to show. */\n  unsigned int filtered_lines;\n\n  /** Previously called key action. */\n  KeyBindingAction prev_action;\n  /** Time previous key action was executed. */\n  xcb_timestamp_t last_button_press;\n\n  /** Indicate view should terminate */\n  int quit;\n  /** Indicate if we should absorb the key release */\n  int skip_absorb;\n  /** The selected line (in the unfiltered list) */\n  unsigned int selected_line;\n  /** The previously selected line (in the unfiltered list) */\n  unsigned int previous_line;\n  /** The return state of the view */\n  MenuReturn retv;\n  /** Monitor #workarea the view is displayed on */\n  workarea mon;\n\n  /** #box holding the different modes buttons */\n  box *sidebar_bar;\n  /** number of modes to display */\n  unsigned int num_modes;\n  /** Array of #textbox that act as buttons for switching modes */\n  textbox **modes;\n\n  /** Total rows. */\n  textbox *tb_total_rows;\n  /** filtered rows */\n  textbox *tb_filtered_rows;\n\n  /** Extra icon widget that shows the current selected entries text. */\n  textbox *tb_current_entry;\n  /** Extra icon widget that shows the current selected entries icon. */\n  icon *icon_current_entry;\n\n  /** Settings of the menu */\n  MenuFlags menu_flags;\n  /** If mouse was within view previously */\n  int mouse_seen;\n  /** Flag indicating if view needs to be reloaded. */\n  int reload;\n  /** The function to be called when finalizing this view */\n  void (*finalize)(struct RofiViewState *state);\n\n  /** Width of the view */\n  int width;\n  /** Height of the view */\n  int height;\n  /** X position of the view */\n  int x;\n  /** Y position of the view */\n  int y;\n\n#ifdef ENABLE_WAYLAND\n  /** wayland */\n  display_buffer_pool *pool;\n  gboolean frame_callback;\n#endif\n\n  /** Position and target of the mouse. */\n  struct {\n    /** X position */\n    int x;\n    /** Y position */\n    int y;\n    /** Widget being targeted. */\n    widget *motion_target;\n  } mouse;\n\n  /** Regexs used for matching */\n  rofi_int_matcher **tokens;\n  /** For case-sensitivity */\n  gboolean case_sensitive;\n};\n/** @} */\n\ntypedef struct _view_proxy {\n  void (*update)(struct RofiViewState *state, gboolean qr);\n  void (*temp_configure_notify)(struct RofiViewState *state,\n                                xcb_configure_notify_event_t *xce);\n  void (*temp_click_to_exit)(struct RofiViewState *state, xcb_window_t target);\n  void (*frame_callback)(void);\n\n  void (*queue_redraw)(void);\n\n  void (*set_window_title)(const char *title);\n  void (*calculate_window_position)(struct RofiViewState *state);\n  void (*calculate_window_width)(struct RofiViewState *state);\n  int (*calculate_window_height)(struct RofiViewState *state);\n  void (*window_update_size)(struct RofiViewState *state);\n  void (*set_cursor)(RofiCursorType type);\n  void (*ping_mouse)(struct RofiViewState *state);\n\n  void (*cleanup)(void);\n  void (*hide)(void);\n  void (*reload)(void);\n  void (*__create_window)(MenuFlags menu_flags);\n  xcb_window_t (*get_window)(void);\n\n  void (*get_current_monitor)(int *width, int *height);\n\n  void (*set_size)(struct RofiViewState *state, gint width, gint height);\n  void (*get_size)(struct RofiViewState *state, gint *width, gint *height);\n\n  void (*pool_refresh)(void);\n} view_proxy;\n\ntypedef struct {\n  char *string;\n  int index;\n} EntryHistoryIndex;\n\n/**\n * Structure holding cached state.\n */\nstruct _rofi_view_cache_state {\n  /** main x11 windows */\n  xcb_window_t main_window;\n  /** Main flags */\n  MenuFlags flags;\n  /** List of stacked views */\n  GQueue views;\n  /** timeout for reloading */\n  guint refilter_timeout;\n  /* amount of time refiltering delay got reset */\n  guint refilter_timeout_count;\n\n  /** if filtering takes longer then this time,\n   * reduce the amount of refilters. */\n  double max_refilter_time;\n  /** enable the reduced refilter mode. */\n  gboolean delayed_mode;\n  /** timeout handling */\n  guint user_timeout;\n  /** timeout overlay */\n  guint overlay_timeout;\n  /** Entry box */\n  gboolean entry_history_enable;\n  /** Array with history entriy input. */\n  EntryHistoryIndex *entry_history;\n  /** Length of the array */\n  gssize entry_history_length;\n  /** The current index being viewed. */\n  gssize entry_history_index;\n};\nextern struct _rofi_view_cache_state CacheState;\n\nvoid rofi_view_update(struct RofiViewState *state, gboolean qr);\nvoid rofi_view_calculate_window_position(struct RofiViewState *state);\nvoid rofi_view_calculate_window_width(struct RofiViewState *state);\nint rofi_view_calculate_window_height(struct RofiViewState *state);\nvoid rofi_view_window_update_size(struct RofiViewState *state);\nvoid rofi_view_refilter(struct RofiViewState *state);\nvoid rofi_view_set_window_title(const char *title);\n\n#endif\n"
  },
  {
    "path": "include/view.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_VIEW_H\n#define ROFI_VIEW_H\n\n#include \"mode.h\"\n#include \"widgets/widget.h\"\n#include \"widgets/textbox.h\"\n#include <pango/pango.h>\n#ifdef ENABLE_XCB\n#include <xcb/xcb.h>\n#else\n#include \"xcb-dummy.h\"\n#endif\n/**\n * @defgroup View View\n *\n * The rofi Menu view.\n * @{\n * @}\n */\n\n/**\n * @defgroup ViewHandle ViewHandle\n * @ingroup View\n *\n * @{\n */\ntypedef struct RofiViewState RofiViewState;\ntypedef enum {\n  /** Create a menu for entering text */\n  MENU_NORMAL = 0,\n  /** Create a menu for entering passwords */\n  MENU_PASSWORD = 1,\n  /** Create amanaged window. */\n  MENU_NORMAL_WINDOW = 2,\n  /** ERROR dialog */\n  MENU_ERROR_DIALOG = 4,\n  /** Create transient window. */\n  MENU_TRANSIENT_WINDOW = 8,\n} MenuFlags;\n\n/**\n * @param sw the Mode to show.\n * @param input A pointer to a string where the inputted data is placed.\n * @param menu_flags   Flags indicating state of the menu.\n * @param finalize the finalize callback\n *\n * Main menu callback.\n *\n * @returns The command issued (see MenuReturn)\n */\nRofiViewState *rofi_view_create(Mode *sw, const char *input,\n                                MenuFlags menu_flags,\n                                void (*finalize)(RofiViewState *));\n\n/**\n * @param state The Menu Handle\n *\n * Check if a finalize function is set, and if sets executes it.\n */\nvoid rofi_view_finalize(RofiViewState *state);\n\n/**\n * @param state the Menu handle\n *\n * Get the return value associated to the users action.\n *\n * @returns the return value\n */\nMenuReturn rofi_view_get_return_value(const RofiViewState *state);\n/**\n * @param state the Menu handle\n *\n * Returns the index of the next visible position.\n *\n * @return the next position.\n */\nunsigned int rofi_view_get_next_position(const RofiViewState *state);\n/**\n * @param state the Menu handle\n * @param text The text to add to the input box\n *\n * Update the state if needed.\n */\nvoid rofi_view_handle_text(RofiViewState *state, const char *text);\n/**\n * @param state the Menu handle\n * @param x The X coordinates of the motion\n * @param y The Y coordinates of the motion\n * @param find_mouse_target if we should handle pure mouse motion\n *\n * Update the state if needed.\n */\nvoid rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y,\n                                   gboolean find_mouse_target);\n/**\n * @param state the Menu handle\n *\n * Update the state if needed.\n */\nvoid rofi_view_maybe_update(RofiViewState *state);\nvoid rofi_view_temp_configure_notify(RofiViewState *state,\n                                     xcb_configure_notify_event_t *xce);\nvoid rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target);\n/**\n * Update the state if needed.\n */\nvoid rofi_view_frame_callback(void);\n/**\n * @param state the Menu handle\n *\n * @returns returns if this state is completed.\n */\nunsigned int rofi_view_get_completed(const RofiViewState *state);\n/**\n * @param state the Menu handle\n *\n * @returns the raw user input.\n */\nconst char *rofi_view_get_user_input(const RofiViewState *state);\n\n/**\n * @param state The Menu Handle\n * @param selected_line The line to select.\n *\n * Select a line.\n */\nvoid rofi_view_set_selected_line(RofiViewState *state,\n                                 unsigned int selected_line);\n\n/**\n * @param state The Menu Handle\n *\n * Get the selected line.\n *\n * @returns the selected line or UINT32_MAX if none selected.\n */\nunsigned int rofi_view_get_selected_line(const RofiViewState *state);\n/**\n * @param state The Menu Handle\n *\n * Restart the menu so it can be displayed again.\n * Resets RofiViewState::quit and RofiViewState::retv.\n */\nvoid rofi_view_restart(RofiViewState *state);\n\n/**\n * @param state The handle to the view\n * @param scope The scope of the action\n * @param action The action\n *\n * @returns TRUE if action was handled.\n */\ngboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope,\n                                guint action);\n\n/**\n * @param state The handle to the view\n * @param scope The scope of the action\n * @param action The action\n */\nvoid rofi_view_trigger_action(RofiViewState *state, BindingsScope scope,\n                              guint action);\n\n/**\n * @param state The handle to the view\n *\n * Free's the memory allocated for this handle.\n * After a call to this function, state is invalid and can no longer be used.\n */\nvoid rofi_view_free(RofiViewState *state);\n/** @} */\n/**\n * @defgroup ViewGlobal ViewGlobal\n * @ingroup View\n *\n * Global menu view functions.\n * These do not work on the view itself but modifies the global state.\n * @{\n */\n\n/**\n * Get the current active view Handle.\n *\n * @returns the active view handle or NULL\n */\nRofiViewState *rofi_view_get_active(void);\n\n/**\n  * Get the current active textbox with the user input.\n  *\n  * @returns the active textbox or NULL\n  */\ntextbox *rofi_view_get_active_text(void);\n\n/**\n * @param state the new active view handle.\n *\n * Set the current active view Handle, If NULL passed a queued  view is popped\n * from stack.\n *\n */\n\nvoid rofi_view_set_active(RofiViewState *state);\n\n/**\n * @param state remove view handle.\n *\n * remove state handle from queue, if current view, pop view from\n * stack.\n *\n */\nvoid rofi_view_remove_active(RofiViewState *state);\n/**\n * @param msg The error message to show.\n * @param markup The error message uses pango markup.\n *\n * The error message to show.\n */\nint rofi_view_error_dialog(const char *msg, int markup);\n\n/**\n * Queue a redraw.\n * This triggers a X11 Expose Event.\n */\nvoid rofi_view_queue_redraw(void);\n\nvoid rofi_view_calculate_window_position(RofiViewState *state);\n\n/**\n * Cleanup internal data of the view.\n */\nvoid rofi_view_cleanup(void);\n\n/**\n * @param state The handle to the view\n *\n * Get the mode currently displayed by the view.\n *\n * @returns the mode currently displayed by the view\n */\nMode *rofi_view_get_mode(RofiViewState *state);\n\n/**\n * Unmap the current view.\n */\nvoid rofi_view_hide(void);\n\n/**\n * Indicate the current view needs to reload its data.\n * This can only be done when *more* information is available.\n *\n * The reloading happens 'lazy', multiple calls might be handled at once.\n */\nvoid rofi_view_reload(void);\n\n/**\n * @param state The handle to the view\n * @param mode The new mode to display\n *\n * Change the current view to show a different mode.\n */\nvoid rofi_view_switch_mode(RofiViewState *state, Mode *mode);\n\n/**\n * @param state The handle to the view\n * @param text An UTF-8 encoded character array with the text to overlay.\n *\n * Overlays text over the current view. Passing NULL for text hides the overlay.\n */\nvoid rofi_view_set_overlay(RofiViewState *state, const char *text);\n/**\n * @param state The handle to the view\n * @param text An UTF-8 encoded character array with the text to overlay.\n *\n * Overlays text over the current view. Passing NULL for text hides the overlay.\n * This message is automatically removed after X seconds.\n */\nvoid rofi_view_set_overlay_timeout(RofiViewState *state, const char *text);\n\n/**\n * @param state The handle to the view.\n *\n * Clears the user entry box, set selected to 0.\n */\nvoid rofi_view_clear_input(RofiViewState *state);\n\n/**\n * @param menu_flags The state of the new window.\n *\n * Creates the internal 'Cached' window that gets reused between views.\n * TODO: Internal call to view exposed.\n */\nvoid __create_window(MenuFlags menu_flags);\n\n/**\n * Get the handle of the main window.\n *\n * @returns the xcb_window_t for rofi's view or XCB_WINDOW_NONE.\n */\nxcb_window_t rofi_view_get_window(void);\n/** @} */\n\n/**\n * @defgroup ViewThreadPool ViewThreadPool\n * @ingroup View\n *\n * The view can (optionally) keep a set of worker threads around to parallize\n * work. This includes filtering and sorting.\n *\n * @{\n */\n/**\n * Initialize the threadpool\n */\nvoid rofi_view_workers_initialize(void);\n/**\n * Stop all threads and free the resources used by the threadpool\n */\nvoid rofi_view_workers_finalize(void);\n\n/**\n * @param width the width of the monitor.\n * @param height the height of the monitor.\n *\n * Return the current monitor workarea.\n *\n */\nvoid rofi_view_get_current_monitor(int *width, int *height);\n\n/**\n * Takes a screenshot.\n */\nvoid rofi_capture_screenshot(void);\n/**\n * Set the window title.\n */\nvoid rofi_view_set_window_title(const char *title);\n\nvoid rofi_view_set_size(RofiViewState *state, gint width, gint height);\n\nvoid rofi_view_get_size(RofiViewState *state, gint *width, gint *height);\n\nvoid rofi_view_ping_mouse(RofiViewState *state);\n\nvoid rofi_view_set_window_title(const char *title);\nvoid rofi_view_pool_refresh(void);\n\nvoid rofi_view_set_cursor(RofiCursorType type);\n\n/**\n * Input history\n */\n\nvoid input_history_save(void);\nvoid input_history_initialize(void);\n\nstruct _view_proxy;\n\n/* Implementations */\nextern const struct _view_proxy *xcb_view_proxy;\n#ifdef ENABLE_WAYLAND\nextern const struct _view_proxy *wayland_view_proxy;\n#endif\n\nvoid view_init(const struct _view_proxy *view_in);\n\n/**\n  @param state The window state handle\n  @param mode The pango ellipsize mode to user\n * set ellipsize mode to start.\n */\nvoid rofi_view_ellipsize_listview(RofiViewState *state,\n                                  PangoEllipsizeMode mode);\n\n/**\n * @param new_x New XIM window x pos\n * @param new_y New XIM window y pos\n *\n * Updates the XIM window position to new_x and new_y, relative to the\n * main_window\n */\ngboolean rofi_set_im_window_pos(int new_x, int new_y);\n\n/**\n * @param wid to test.\n * @param action the action done.\n * @param x [unused]\n * @param y [unsued]\n * @param user_data\n *\n * textbux widget trigger action function.\n *\n * @return the result.\n */\nWidgetTriggerActionResult textbox_button_trigger_action(\n    widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,\n    G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data);\n\n/** @} */\n#endif\n"
  },
  {
    "path": "include/wayland-internal.h",
    "content": "#ifndef ROFI_WAYLAND_INTERNAL_H\n#define ROFI_WAYLAND_INTERNAL_H\n\n#include <cairo.h>\n#include <glib.h>\n#include <libgwater-wayland.h>\n#include <nkutils-bindings.h>\n#include <wayland-client.h>\n#include <xkbcommon/xkbcommon.h>\n\n#include \"wayland.h\"\n\ntypedef enum {\n  WAYLAND_GLOBAL_COMPOSITOR,\n  WAYLAND_GLOBAL_SHM,\n  WAYLAND_GLOBAL_LAYER_SHELL,\n  WAYLAND_GLOBAL_KEYBOARD_SHORTCUTS_INHIBITOR,\n  WAYLAND_GLOBAL_CURSOR_SHAPE,\n  _WAYLAND_GLOBAL_SIZE,\n} wayland_global_name;\n\ntypedef struct {\n  uint32_t button;\n  char modifiers;\n  gint x, y;\n  gboolean pressed;\n  guint32 time;\n} widget_button_event;\n\ntypedef struct {\n  gint x, y;\n  guint32 time;\n} widget_motion_event;\n\ntypedef struct _wayland_seat wayland_seat;\n\ntypedef struct {\n  void *offer;\n} clipboard_data;\n\ntypedef struct {\n  GMainLoop *main_loop;\n  GWaterWaylandSource *main_loop_source;\n  struct wl_display *display;\n  struct wl_registry *registry;\n  uint32_t global_names[_WAYLAND_GLOBAL_SIZE];\n  struct wl_compositor *compositor;\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  struct wp_cursor_shape_manager_v1 *cursor_shape_manager;\n#endif\n\n  struct wl_data_device_manager *data_device_manager;\n  struct zwp_primary_selection_device_manager_v1\n      *primary_selection_device_manager;\n\n  struct zwlr_layer_shell_v1 *layer_shell;\n\n  struct zwp_keyboard_shortcuts_inhibit_manager_v1 *kb_shortcuts_inhibit_manager;\n\n  struct wl_shm *shm;\n  size_t buffer_count;\n  struct {\n    char *theme_name;\n    RofiCursorType type;\n    struct wl_cursor_theme *theme;\n    struct wl_cursor *cursor;\n    struct wl_cursor_image *image;\n    struct wl_surface *surface;\n    struct wl_callback *frame_cb;\n    guint scale;\n  } cursor;\n  GHashTable *seats;\n  GHashTable *seats_by_name;\n  wayland_seat *last_seat;\n  GHashTable *outputs;\n  struct wl_surface *surface;\n  struct zwlr_layer_surface_v1 *wlr_surface;\n  struct wl_callback *frame_cb;\n  size_t scales[3];\n  int32_t scale;\n  NkBindingsSeat *bindings_seat;\n\n  clipboard_data clipboards[2];\n\n  uint32_t layer_width;\n  uint32_t layer_height;\n\n  struct zwp_text_input_manager_v3 *text_input_manager;\n} wayland_stuff;\n\nstruct _wayland_seat {\n  wayland_stuff *context;\n  uint32_t global_name;\n  struct wl_seat *seat;\n  gchar *name;\n  struct {\n    xkb_keycode_t key;\n    GSource *source;\n    int32_t rate;\n    int32_t delay;\n  } repeat;\n  uint32_t serial;\n  uint32_t pointer_serial;\n  struct wl_keyboard *keyboard;\n  struct wl_pointer *pointer;\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  struct wp_cursor_shape_device_v1 *cursor_shape_device;\n#endif\n  struct wl_data_device *data_device;\n  struct zwp_primary_selection_device_v1 *primary_selection_device;\n\n  enum wl_pointer_axis_source axis_source;\n  widget_button_event button;\n  widget_motion_event motion;\n  struct {\n    gint vertical;\n    gint horizontal;\n  } wheel;\n  struct {\n    double vertical;\n    double horizontal;\n  } wheel_continuous;\n\n  struct zwp_text_input_v3 *text_input;\n};\n\n/* Supported interface versions */\n#define WL_COMPOSITOR_INTERFACE_VERSION 3\n#define WL_SHM_INTERFACE_VERSION 1\n#define WL_SEAT_INTERFACE_MIN_VERSION 5\n#define WL_SEAT_INTERFACE_MAX_VERSION 8\n#define WL_OUTPUT_INTERFACE_MIN_VERSION 2\n#define WL_OUTPUT_INTERFACE_MAX_VERSION 4\n#define WL_LAYER_SHELL_INTERFACE_VERSION 1\n#define WL_KEYBOARD_SHORTCUTS_INHIBITOR_INTERFACE_VERSION 1\n\nextern wayland_stuff *wayland;\n\n#endif\n"
  },
  {
    "path": "include/wayland.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_WAYLAND_H\n#define ROFI_WAYLAND_H\n\n#include <cairo.h>\n#include <glib.h>\n\n#include \"display.h\"\n\ntypedef struct _display_buffer_pool display_buffer_pool;\ndisplay_buffer_pool *display_buffer_pool_new(gint width, gint height);\nvoid display_buffer_pool_free(display_buffer_pool *pool);\n\ncairo_surface_t *display_buffer_pool_get_next_buffer(display_buffer_pool *pool);\nvoid display_surface_commit(cairo_surface_t *surface);\n\ngboolean display_get_surface_dimensions(int *width, int *height);\nvoid display_set_surface_dimensions(int width, int height, int x_margin,\n                                    int y_margin, int loc);\n\nvoid wayland_display_set_cursor_type(RofiCursorType type);\n\n/**\n * Tries to guess the DPI.\n *\n * @returns an guess for the dpi, or -1 if no guess could be made.\n */\ndouble wayland_get_dpi_estimation(void);\n\n#endif\n"
  },
  {
    "path": "include/widgets/box.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_HBOX_H\n#define ROFI_HBOX_H\n\n#include \"rofi-types.h\"\n#include \"widget.h\"\n\n/**\n * @defgroup box box\n * @ingroup widget\n *\n * Widget used to pack multiple widgets either horizontally or vertically.\n * It supports packing widgets horizontally or vertically. Child widgets are\n * always expanded to the maximum size in the opposite direction of the packing\n * direction. e.g. vertically packed widgets use the full box width.\n *\n * @{\n */\n\n/**\n * Abstract handle to the box widget internal state.\n */\ntypedef struct _box box;\n\n/**\n * @param parent The widgets parent.\n * @param name The name of the widget.\n * @param type The packing direction of the newly created box.\n *\n * @returns a newly created box, free with #widget_free\n */\nbox *box_create(widget *parent, const char *name, RofiOrientation type);\n\n/**\n * @param box   Handle to the box widget.\n * @param child Handle to the child widget to pack.\n * @param expand If the child widget should expand and use all available space.\n *\n * Add a widget to the box.\n */\nvoid box_add(box *box, widget *child, gboolean expand);\n/**@}*/\n#endif // ROFI_HBOX_H\n"
  },
  {
    "path": "include/widgets/container.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_CONTAINER_H\n#define ROFI_CONTAINER_H\n\n#include \"widget.h\"\n\n/**\n * @defgroup container container\n * @ingroup widget\n *\n *\n * @{\n */\n\n/**\n * Abstract handle to the container widget internal state.\n */\ntypedef struct _container container;\n\n/**\n * @param parent The widget's parent\n * @param name The name of the widget.\n *\n * @returns a newly created container, free with #widget_free\n */\ncontainer *container_create(widget *parent, const char *name);\n\n/**\n * @param container   Handle to the container widget.\n * @param child Handle to the child widget to pack.\n *\n * Add a widget to the container.\n */\nvoid container_add(container *container, widget *child);\n/**@}*/\n#endif // ROFI_CONTAINER_H\n"
  },
  {
    "path": "include/widgets/icon.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2018 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_ICON_H\n#define ROFI_ICON_H\n\n#include \"widget.h\"\n\n/**\n * @defgroup icon icon\n * @ingroup widget\n *\n *\n * @{\n */\n\n/**\n * Abstract handle to the icon widget internal state.\n */\ntypedef struct _icon icon;\n\n/**\n * @param parent The widget's parent\n * @param name The name of the widget.\n *\n * @returns a newly created icon, free with #widget_free\n */\nicon *icon_create(widget *parent, const char *name);\n\n/**\n * @param icon The icon widget handle.\n * @param size  The size of the icon.\n *\n */\nvoid icon_set_size(widget *icon, const int size);\n\n/**\n * @param icon_widget The icon widget handle.\n * @param surf The surface to display.\n */\nvoid icon_set_surface(icon *icon_widget, cairo_surface_t *surf);\n/**@}*/\n#endif // ROFI_ICON_H\n"
  },
  {
    "path": "include/widgets/listview.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_LISTVIEW_H\n#define ROFI_LISTVIEW_H\n\n#include \"widgets/textbox.h\"\n#include <pango/pango.h>\n\n/**\n * @defgroup listview listview\n * @ingroup widget\n *\n * @{\n */\n\n/**\n * Handle to the listview.\n * No internal fields should be accessed directly.\n */\ntypedef struct _listview listview;\n\n/**\n * The scrolling type used in the list view\n */\ntypedef enum {\n  /** Flip through the pages. */\n  LISTVIEW_SCROLL_PER_PAGE,\n  /** keep selected item centered */\n  LISTVIEW_SCROLL_CONTINIOUS\n} ScrollType;\n\n/**\n * @param tb The textbox to set\n * @param ico The icon to set\n * @param entry The position of the textbox\n * @param udata User data\n * @param type The textbox font style to apply to this entry (normal, selected,\n * alternative row)\n * @param full If true Set both text and style.\n *\n * Update callback, this is called to set the value of each (visible) element.\n */\ntypedef void (*listview_update_callback)(textbox *tb, icon *ico,\n                                         unsigned int entry, void *udata,\n                                         TextBoxFontType *type, gboolean full);\n\n/**\n * @param lv The listview\n * @param index the selected row\n * @param udata user data\n *\n * Selection changed callback.\n */\ntypedef void (*listview_selection_changed_callback)(listview *lv,\n                                                    unsigned int index,\n                                                    void *udata);\n/**\n * Callback when a element is activated.\n */\ntypedef void (*listview_mouse_activated_cb)(listview *, gboolean, void *);\n\n\n/**\n * Callback when current page is changed.\n */\ntypedef void (*listview_page_changed_cb)(void);\n\n\n/**\n * @param parent The widget's parent.\n * @param name The name of the to be created widget.\n * @param cb The update callback.\n * @param page_cb The page change callback.\n * @param udata The user data to pass to the callback\n * @param eh The height of one element\n * @param reverse Reverse the listview order.\n *\n * @returns a new listview\n */\nlistview *listview_create(widget *parent, const char *name,\n                          listview_update_callback cb,\n                          listview_page_changed_cb page_cb, void *udata,\n                          unsigned int eh, gboolean reverse);\n\n/**\n * Set the selection changed callback.\n */\nvoid listview_set_selection_changed_callback(\n    listview *lv, listview_selection_changed_callback cb, void *udata);\n\n/**\n * @param lv The listview handle\n * @param rows Number of elements\n *\n * Set the maximum number of elements to display.\n */\nvoid listview_set_num_elements(listview *lv, unsigned int rows);\n\n/**\n * @param lv The listview handle\n * @param selected The row index to select\n *\n * Select the row, if selected > the number of rows, it selects the last one.\n */\nvoid listview_set_selected(listview *lv, unsigned int selected);\n\n/**\n * @param lv The listview handle\n *\n * Returns the selected row.\n *\n * @returns the selected row.\n */\nunsigned int listview_get_selected(listview *lv);\n\n/**\n * @param lv The listview handle\n *\n * Move the selection next element.\n * - Wrap around.\n */\nvoid listview_nav_next(listview *lv);\n/**\n * @param lv The listview handle\n *\n * Move the selection previous element.\n * - Wrap around.\n */\nvoid listview_nav_prev(listview *lv);\n\n/**\n * @param lv The listview handle\n *\n * Move the selection one row up.\n * - Wrap around.\n */\nvoid listview_nav_up(listview *lv);\n/**\n * @param lv listview handle.\n *\n * Move the selection one row down.\n * - Wrap around.\n */\nvoid listview_nav_down(listview *lv);\n/**\n * @param lv The listview handle\n *\n * Move the selection one column to the right.\n * - No wrap around.\n * - Do not move to top row when at start.\n */\nvoid listview_nav_right(listview *lv);\n/**\n * @param lv The listview handle\n *\n * Move the selection one column to the left.\n * - No wrap around.\n */\nvoid listview_nav_left(listview *lv);\n/**\n * @param lv The listview handle\n *\n * Move the selection one page down.\n * - No wrap around.\n * - Clip at top/bottom\n */\nvoid listview_nav_page_next(listview *lv);\n\n/**\n * @param lv The listview handle\n *\n * Move the selection one page up.\n * - No wrap around.\n * - Clip at top/bottom\n */\nvoid listview_nav_page_prev(listview *lv);\n\n/**\n * @param lv Handler to the listview object\n * @param enabled enable\n *\n * Hide the scrollbar.\n */\nvoid listview_set_show_scrollbar(listview *lv, gboolean enabled);\n/**\n * @param lv Handler to the listview object\n * @param width Width in pixels\n *\n * Set the width of the scrollbar\n */\nvoid listview_set_scrollbar_width(listview *lv, unsigned int width);\n\n/**\n * @param lv Handler to the listview object\n * @param cycle True for cycle mode\n *\n * Set cycle mode. On last entry go to first.\n */\nvoid listview_set_cycle(listview *lv, gboolean cycle);\n/**\n * @param lv Handler to the listview object\n * @param type ScrollType\n *\n * Set the scroll type ScrollType::LISTVIEW_SCROLL_CONTINIOUS or\n * ScrollType::LISTVIEW_SCROLL_PER_PAGE\n */\nvoid listview_set_scroll_type(listview *lv, ScrollType type);\n\n/**\n * @param lv Handler to the listview object\n * @param cb The callback\n * @param udata User data\n *\n * Set the mouse activated callback.\n */\nvoid listview_set_mouse_activated_cb(listview *lv,\n                                     listview_mouse_activated_cb cb,\n                                     void *udata);\n\n/**\n * @param lv Handler to the listview object.\n *\n * Get the fixed-height property.\n *\n * @returns get fixed-height.\n */\ngboolean listview_get_fixed_num_lines(listview *lv);\n\n/**\n * @param lv Handler to the listview object.\n *\n * Set fixed num lines mode.\n */\nvoid listview_set_fixed_num_lines(listview *lv);\n\n/**\n * @param lv Handler to the listview object.\n * @param max_lines the maximum number of lines to display.\n *\n * Set the maximum number of lines to display.\n */\nvoid listview_set_max_lines(listview *lv, unsigned int max_lines);\n\n/**\n * @param lv Handler to the listview object.\n *\n * Set ellipsize mode.\n */\nvoid listview_toggle_ellipsizing(listview *lv);\n\n/**\n * @param lv Handler to the listview object.\n * @param mode The ellipsize mode to set.\n *\n * Set ellipsize mode on the listview.\n */\n\nvoid listview_set_ellipsize(listview *lv, PangoEllipsizeMode mode);\n\n/**\n * @param lv Handler to the listview object.\n * @param filtered boolean indicating if list is filtered.\n *\n */\nvoid listview_set_filtered(listview *lv, gboolean filtered);\n/** @} */\n\n#endif // ROFI_LISTVIEW_H\n"
  },
  {
    "path": "include/widgets/scrollbar.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_SCROLLBAR_H\n#define ROFI_SCROLLBAR_H\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <cairo.h>\n\n/**\n * @defgroup Scrollbar Scrollbar\n * @ingroup widget\n *\n * @{\n */\n/**\n * Internal structure for the scrollbar.\n */\ntypedef struct _scrollbar {\n  widget widget;\n  unsigned int length;\n  unsigned int pos;\n  unsigned int pos_length;\n  RofiDistance width;\n} scrollbar;\n\n/**\n * @param parent The parent widget.\n * @param name  The name of the widget.\n *\n * Create a new scrollbar\n *\n * @returns the scrollbar object.\n */\nscrollbar *scrollbar_create(widget *parent, const char *name);\n\n/**\n * @param sb scrollbar object\n * @param pos_length new length\n *\n * set the length of the handle relative to the max value of bar.\n */\nvoid scrollbar_set_handle_length(scrollbar *sb, unsigned int pos_length);\n\n/**\n * @param sb scrollbar object\n * @param pos new position\n *\n * set the position of the handle relative to the set max value of bar.\n */\nvoid scrollbar_set_handle(scrollbar *sb, unsigned int pos);\n\n/**\n * @param sb scrollbar object\n * @param max the new max\n *\n * set the max value of the bar.\n */\nvoid scrollbar_set_max_value(scrollbar *sb, unsigned int max);\n\n/**\n * @param sb scrollbar object\n * @param y  clicked position\n *\n * Calculate the position of the click relative to the max value of bar\n */\nguint scrollbar_scroll_get_line(const scrollbar *sb, int y);\n\n/**@}*/\n#endif // ROFI_SCROLLBAR_H\n"
  },
  {
    "path": "include/widgets/textbox.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_TEXTBOX_H\n#define ROFI_TEXTBOX_H\n\n#include \"keyb.h\"\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <cairo.h>\n#include <pango/pango-fontmap.h>\n#include <pango/pango.h>\n#include <pango/pangocairo.h>\n\n/**\n * @defgroup Textbox Textbox\n * @ingroup widget\n *\n * @{\n */\n\n/** Cache to hold font descriptions. This it to avoid having to lookup each\n * time. */\ntypedef struct TBFontConfig {\n  /** Font description */\n  PangoFontDescription *pfd;\n  /** Font metrics */\n  PangoFontMetrics *metrics;\n  /** height */\n  double height;\n} TBFontConfig;\n/**\n * Internal structure of a textbox widget.\n * TODO make this internal to textbox\n */\ntypedef struct {\n  widget widget;\n  unsigned long flags;\n  short cursor;\n  char *text;\n  char *placeholder;\n  int show_placeholder;\n  PangoLayout *layout;\n  int tbft;\n  int markup;\n  int changed;\n\n  int blink;\n  guint blink_timeout;\n\n  double yalign;\n  double xalign;\n\n  int cursor_x_pos;\n\n  TBFontConfig *tbfc;\n\n  PangoEllipsizeMode emode;\n  \n  const char *password_mask_char;\n\n  const char *theme_name;\n} textbox;\n\n/**\n * Flags for configuring textbox behaviour and looks during creation.\n */\ntypedef enum {\n  TB_AUTOHEIGHT = 1 << 0,\n  TB_AUTOWIDTH = 1 << 1,\n  TB_EDITABLE = 1 << 19,\n  TB_MARKUP = 1 << 20,\n  TB_WRAP = 1 << 21,\n  TB_PASSWORD = 1 << 22,\n} TextboxFlags;\n/**\n * Flags indicating current state of the textbox.\n */\ntypedef enum {\n  /** Normal */\n  NORMAL = 0,\n  /** Text in box is urgent. */\n  URGENT = 1,\n  /** Text in box is active. */\n  ACTIVE = 2,\n  /** Text in box is selected. */\n  SELECTED = 4,\n  /** Text in box has pango markup. */\n  MARKUP = 8,\n\n  /** Text is on an alternate row */\n  ALT = 16,\n  /** Render font highlighted (inverted colors.) */\n  HIGHLIGHT = 32,\n  /** Mask for alternate and highlighted */\n  FMOD_MASK = (ALT | HIGHLIGHT),\n  /** Mask of bits indicating state */\n  STATE_MASK = ~(SELECTED | MARKUP | ALT | HIGHLIGHT)\n} TextBoxFontType;\n\n/**\n * @param parent The widget's parent.\n * @param type The type of the to be created widget.\n * @param name The name of the to be created widget.\n * @param flags #TextboxFlags indicating the type of textbox.\n * @param tbft #TextBoxFontType current state of textbox.\n * @param text initial text to display.\n * @param xalign Set the Xalign value.\n * @param yalign set the yalign value.\n *\n * Create a new textbox widget.\n *\n * free with #widget_free\n * @returns a new #textbox\n */\ntextbox *textbox_create(widget *parent, WidgetType type, const char *name,\n                        TextboxFlags flags, TextBoxFontType tbft,\n                        const char *text, double xalign, double yalign);\n/**\n * @param tb  Handle to the textbox\n * @param tbft The style of font to render.\n *\n * Set the font render style.\n */\nvoid textbox_font(textbox *tb, TextBoxFontType tbft);\n\n/**\n * @param tb  Handle to the textbox\n * @param text The text to show in the textbox\n *\n * Set the text to show. Cursor is moved to end (if visible)\n */\nvoid textbox_text(textbox *tb, const char *text);\n\n/**\n * @param tb Handle to the textbox\n * @param action the #KeyBindingAction to execute on textbox\n *\n * Execute an action on the textbox.\n *\n * @return TRUE if action was taken.\n */\nint textbox_keybinding(textbox *tb, KeyBindingAction action);\n/**\n * @param tb Handle to the textbox\n * @param pad The text to insert\n * @param pad_len the length of the text\n *\n * The text should be one insert from a keypress..  the first gunichar is\n * validated to be (or not) control return TRUE if inserted\n */\ngboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len);\n\n/**\n * @param tb  Handle to the textbox\n * @param pos New cursor position\n *\n * Set the cursor position (string index)\n */\nvoid textbox_cursor(textbox *tb, int pos);\n\n/**\n * @param tb   Handle to the textbox\n * @param char_pos  The position to insert the string at\n * @param str  The string to insert.\n * @param slen The length of the string.\n *\n * Insert the string str at position pos.\n */\nvoid textbox_insert(textbox *tb, const int char_pos, const char *str,\n                    const int slen);\n\n/**\n * Setup the cached fonts. This is required to do\n * before any of the textbox_ functions is called.\n * Clean with textbox_cleanup()\n */\nvoid textbox_setup(void);\n\n/**\n * Cleanup the allocated colors and fonts by textbox_setup().\n */\nvoid textbox_cleanup(void);\n\n/**\n * @param tb Handle to the textbox\n *\n * Get the height of the textbox\n *\n * @returns the height of the textbox in pixels.\n */\nint textbox_get_height(const textbox *tb);\n\n/**\n * @param tb Handle to the textbox\n *\n * Get the height of the rendered string.\n *\n * @returns the height of the string in pixels.\n */\nint textbox_get_font_height(const textbox *tb);\n\n/**\n * @param tb Handle to the textbox\n *\n * Get the width of the rendered string.\n *\n * @returns the width of the string in pixels.\n */\nint textbox_get_font_width(const textbox *tb);\n\n/**\n * Estimate the width of a character.\n *\n * @returns the width of a character in pixels.\n */\ndouble textbox_get_estimated_char_width(void);\n\n/**\n * Estimate the width of a 0.\n *\n * @returns the width of a 0 in pixels.\n */\ndouble textbox_get_estimated_ch(void);\n/**\n * Estimate the height of a character.\n *\n * @returns the height of a character in pixels.\n */\ndouble textbox_get_estimated_char_height(void);\n\n/**\n * @param tb Handle to the textbox\n * @param pos The start position\n * @param dlen The length\n *\n * Remove dlen bytes from position pos.\n */\nvoid textbox_delete(textbox *tb, int pos, int dlen);\n\n/**\n * @param tb Handle to the textbox\n * @param x The new horizontal position to place with textbox\n * @param y The new vertical position to place with textbox\n * @param w The new width of the textbox\n * @param h The new height of the textbox\n *\n * Move and resize the textbox.\n * TODO remove for #widget_resize and #widget_move\n */\nvoid textbox_moveresize(textbox *tb, int x, int y, int w, int h);\n\n/**\n * @param tb Handle to the textbox\n * @param eh The number of rows to display\n *\n * Get the (estimated) with of a character, can be used to calculate window\n * width. This includes padding.\n *\n * @returns the estimated width of a character.\n */\nint textbox_get_estimated_height(const textbox *tb, int eh);\n/**\n * @param font The name of the font used.\n * @param p The new default PangoContext\n *\n * Set the default pango context (with font description) for all textboxes.\n */\nvoid textbox_set_pango_context(const char *font, PangoContext *p);\n/**\n * @param tb Handle to the textbox\n * @param list New pango attributes\n *\n * Sets list as active pango attributes.\n */\nvoid textbox_set_pango_attributes(textbox *tb, PangoAttrList *list);\n\n/**\n * @param tb Handle to the textbox\n *\n * Get the list of currently active pango attributes.\n *\n * @returns the pango attributes\n */\nPangoAttrList *textbox_get_pango_attributes(textbox *tb);\n\n/**\n * @param tb Handle to the textbox\n *\n * @returns the visible text.\n */\nconst char *textbox_get_visible_text(const textbox *tb);\n\n/**\n * @param wid The handle to the textbox.\n * @param height The height we want the desired width for\n *\n * TODO: is this deprecated by widget::get_desired_width\n *\n * @returns the desired width of the textbox.\n */\nint textbox_get_desired_width(widget *wid, G_GNUC_UNUSED const int height);\n\n/**\n * @param tb  Handle to the textbox\n *\n * Move the cursor to the end of the string.\n */\nvoid textbox_cursor_end(textbox *tb);\n\n/**\n * @param tb  Handle to the textbox\n * @param mode The PangoEllipsizeMode to use displaying the text in the textbox\n *\n * Set the ellipsizing mode used on the string.\n */\nvoid textbox_set_ellipsize(textbox *tb, PangoEllipsizeMode mode);\n\n/**\n * @param tb Handle to the textbox\n *\n * @returns the position of the cursor (0 if no cursor).\n */\nint textbox_get_cursor_x_pos(const textbox *tb);\n\n/**\n * @param tb Handle to the textbox\n *\n * @returns gets a newly allocated copy of the content of the entrybox.\n */\nchar *textbox_get_text(const textbox *tb);\n\n/**\n * @param tb Handle to the textbox\n *\n * @returns the position of the cursor.\n */\nint textbox_get_cursor(const textbox *tb);\n/**@}*/\n#endif // ROFI_TEXTBOX_H\n"
  },
  {
    "path": "include/widgets/widget-internal.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef WIDGET_INTERNAL_H\n#define WIDGET_INTERNAL_H\n\n#include \"theme.h\"\n\n/** Macro for initializing the RofiDistance struct. */\n#define WIDGET_DISTANCE_INIT                                                   \\\n  (RofiDistance) {                                                             \\\n    .base =                                                                    \\\n        {                                                                      \\\n            .distance = 0,                                                     \\\n            .type = ROFI_PU_PX,                                                \\\n            .modtype = ROFI_DISTANCE_MODIFIER_NONE,                            \\\n            .left = NULL,                                                      \\\n            .right = NULL,                                                     \\\n        },                                                                     \\\n    .style = ROFI_HL_SOLID,                                                    \\\n  }\n/** Macro for initializing the RofiPadding struct. */\n#define WIDGET_PADDING_INIT                                                    \\\n  (RofiPadding) {                                                              \\\n    .top = WIDGET_DISTANCE_INIT, .right = WIDGET_DISTANCE_INIT,                \\\n    .bottom = WIDGET_DISTANCE_INIT, .left = WIDGET_DISTANCE_INIT,              \\\n  }\n\n/**\n * Data structure holding the internal state of the Widget\n */\nstruct _widget {\n  /** The type of the widget */\n  WidgetType type;\n  /** X position relative to parent */\n  short x;\n  /** Y position relative to parent */\n  short y;\n  /** Width of the widget */\n  short w;\n  /** Height of the widget */\n  short h;\n  /** RofiPadding */\n  RofiPadding def_margin;\n  RofiPadding def_padding;\n  RofiPadding def_border;\n  RofiPadding def_border_radius;\n  RofiPadding margin;\n  RofiPadding padding;\n  RofiPadding border;\n  RofiPadding border_radius;\n\n  /** Cursor that is set when the widget is hovered */\n  RofiCursorType cursor_type;\n\n  /** enabled or not */\n  gboolean enabled;\n  /** Expand the widget when packed */\n  gboolean expand;\n  /** Place widget at end of parent */\n  gboolean end;\n\n  /** enable/disable border aliasing. */\n  gboolean border_antialiasing;\n  /** enable/disable nvisia workaround. */\n  gboolean border_disable_nvidia_workaround;\n\n  /** Parent widget */\n  struct _widget *parent;\n  /** Internal */\n  gboolean need_redraw;\n  /** get width of widget implementation function */\n  int (*get_width)(struct _widget *);\n  /** get height of widget implementation function */\n  int (*get_height)(struct _widget *);\n  /** draw widget implementation function */\n  void (*draw)(struct _widget *widget, cairo_t *draw);\n  /** resize widget implementation function */\n  void (*resize)(struct _widget *, short, short);\n  /** update widget implementation function */\n  void (*update)(struct _widget *);\n\n  /** Handle mouse motion, used for dragging */\n  gboolean (*motion_notify)(struct _widget *, gint x, gint y);\n\n  int (*get_desired_height)(struct _widget *, const int width);\n  int (*get_desired_width)(struct _widget *, const int height);\n\n  void (*set_state)(struct _widget *, const char *);\n\n  /** widget find_mouse_target callback */\n  widget_find_mouse_target_cb find_mouse_target;\n  /** widget trigger_action callback */\n  widget_trigger_action_cb trigger_action;\n  /** user data for find_mouse_target and trigger_action callback */\n  void *trigger_action_cb_data;\n\n  /** Free widget callback */\n  void (*free)(struct _widget *widget);\n\n  /** Name of widget (used for theming) */\n  char *name;\n  const char *state;\n};\n\n/**\n * @param wid    The widget to initialize.\n * @param parent The widget's parent.\n * @param type The type of the widget.\n * @param name The name of the widget.\n *\n * Initializes the widget structure.\n *\n */\nvoid widget_init(widget *wid, widget *parent, WidgetType type,\n                 const char *name);\n\n/**\n * @param widget The widget handle.\n * @param state  The state of the widget.\n *\n * Set the state of the widget.\n */\nvoid widget_set_state(widget *widget, const char *state);\n\n/**\n * @param wid The widget handle.\n *\n * Get the left padding of the widget.\n *\n * @returns the left padding in pixels.\n */\nint widget_padding_get_left(const widget *wid);\n\n/**\n * @param wid The widget handle.\n *\n * Get the right padding of the widget.\n *\n * @returns the right padding in pixels.\n */\nint widget_padding_get_right(const widget *wid);\n\n/**\n * @param wid The widget handle.\n *\n * Get the top padding of the widget.\n *\n * @returns the top padding in pixels.\n */\nint widget_padding_get_top(const widget *wid);\n\n/**\n * @param wid The widget handle.\n *\n * Get the bottom padding of the widget.\n *\n * @returns the bottom padding in pixels.\n */\nint widget_padding_get_bottom(const widget *wid);\n\n/**\n * @param wid The widget handle.\n *\n * Get width of the content of the widget\n *\n * @returns the widget width, excluding padding.\n */\nint widget_padding_get_remaining_width(const widget *wid);\n/**\n * @param wid The widget handle.\n *\n * Get height of the content of the widget\n *\n * @returns the widget height, excluding padding.\n */\nint widget_padding_get_remaining_height(const widget *wid);\n/**\n * @param wid The widget handle.\n *\n * Get the combined top and bottom padding.\n *\n * @returns the top and bottom padding of the widget in pixels.\n */\nint widget_padding_get_padding_height(const widget *wid);\n/**\n * @param wid The widget handle.\n *\n * Get the combined left and right padding.\n *\n * @returns the left and right padding of the widget in pixels.\n */\nint widget_padding_get_padding_width(const widget *wid);\n#endif // WIDGET_INTERNAL_H\n"
  },
  {
    "path": "include/widgets/widget.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_WIDGET_H\n#define ROFI_WIDGET_H\n#include \"keyb.h\"\n#include <cairo.h>\n#include <glib.h>\n/**\n * @defgroup widget widget\n *\n * Generic abstract widget class. Widgets should 'inherit' from this class\n * (first structure in there structure should be widget). The generic widget\n * implements generic functions like get_width, get_height, draw, resize,\n * update, free and clicked. It also holds information about how the widget\n * should be packed.\n *\n * @{\n */\n\n/**\n * Abstract structure holding internal state of a widget.\n * Structure is elaborated in widget-internal.h\n */\ntypedef struct _widget widget;\n\n/**\n * Type of the widget. It is used to bubble events to the relevant widget.\n */\ntypedef enum {\n  /** Default type */\n  WIDGET_TYPE_UNKNOWN,\n  /** The listview widget */\n  WIDGET_TYPE_LISTVIEW = SCOPE_MOUSE_LISTVIEW,\n  /** An element in the listview */\n  WIDGET_TYPE_LISTVIEW_ELEMENT = SCOPE_MOUSE_LISTVIEW_ELEMENT,\n  /** The input bar edit box */\n  WIDGET_TYPE_EDITBOX = SCOPE_MOUSE_EDITBOX,\n  /** The listview scrollbar */\n  WIDGET_TYPE_SCROLLBAR = SCOPE_MOUSE_SCROLLBAR,\n  /** A widget allowing user to swithc between modes */\n  WIDGET_TYPE_MODE_SWITCHER = SCOPE_MOUSE_MODE_SWITCHER,\n  /** Text-only textbox */\n  WIDGET_TYPE_TEXTBOX_TEXT,\n} WidgetType;\n\n/**\n * Whether and how the action was handled\n */\ntypedef enum {\n  /** The action was ignore and should bubble */\n  WIDGET_TRIGGER_ACTION_RESULT_IGNORED,\n  /** The action was handled directly */\n  WIDGET_TRIGGER_ACTION_RESULT_HANDLED,\n  /** The action was handled and should start the grab for motion events */\n  WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN,\n  /** The action was handled and should stop the grab for motion events */\n  WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END,\n} WidgetTriggerActionResult;\n\n/**\n * @param wid The container widget itself\n * @param type The widget type searched for\n * @param x The X coordination of the mouse event relative to #widget\n * @param y The Y coordination of the mouse event relative to #widget\n *\n * This callback must only iterate over the children of a Widget, and return\n * NULL if none of them is relevant.\n *\n * @returns A child widget if found, NULL otherwise\n */\ntypedef widget *(*widget_find_mouse_target_cb)(widget *wid, WidgetType type,\n                                               gint x, gint y);\n\n/**\n * @param wid The target widget\n * @param action The action value (which enum it is depends on the widget type)\n * @param x The X coordination of the mouse event relative to #widget\n * @param y The Y coordination of the mouse event relative to #widget\n * @param user_data The data passed to widget_set_trigger_action_handler()\n *\n * This callback should handle the action if relevant, and returns whether it\n * did or not.\n *\n * @returns Whether the action was handled or not, see enum values for details\n */\ntypedef WidgetTriggerActionResult (*widget_trigger_action_cb)(widget *wid,\n                                                              guint action,\n                                                              gint x, gint y,\n                                                              void *user_data);\n\n/** Macro to get widget from an implementation (e.g. textbox/scrollbar) */\n#define WIDGET(a) ((widget *)(a))\n\n/**\n * @param wid The widget to check\n * @param x The X position relative to parent window\n * @param y the Y position relative to parent window\n *\n * Check if x,y falls within the widget.\n *\n * @return TRUE if x,y falls within the widget\n */\nint widget_intersect(const widget *wid, int x, int y);\n\n/**\n * @param wid The widget to move\n * @param x The new X position relative to parent window\n * @param y The new Y position relative to parent window\n *\n * Moves the widget.\n */\nvoid widget_move(widget *wid, short x, short y);\n\n/**\n * @param wid Handle to widget\n * @param type The widget type.\n *\n * Set the widget type.\n */\nvoid widget_set_type(widget *wid, WidgetType type);\n\n/**\n * @param wid Handle to widget\n *\n * Check if widget is enabled.\n * @returns TRUE when widget is enabled.\n */\ngboolean widget_enabled(widget *wid);\n\n/**\n * @param wid Handle to widget\n * @param enabled The new state\n *\n * Disable the widget.\n */\nvoid widget_set_enabled(widget *wid, gboolean enabled);\n\n/**\n * @param wid Handle to widget\n *\n * Disable the widget.\n */\nstatic inline void widget_disable(widget *wid) {\n  widget_set_enabled(wid, FALSE);\n}\n/**\n * @param wid Handle to widget\n *\n * Enable the widget.\n */\nstatic inline void widget_enable(widget *wid) { widget_set_enabled(wid, TRUE); }\n\n/**\n * @param wid widget  Handle to the widget\n * @param d The cairo object used to draw itself.\n *\n * Render the textbox.\n */\nvoid widget_draw(widget *wid, cairo_t *d);\n\n/**\n * @param wid Handle to the widget\n *\n * Free the widget and all allocated memory.\n */\nvoid widget_free(widget *wid);\n\n/**\n * @param wid The widget toresize\n * @param w The new width\n * @param h The new height\n *\n * Resizes the widget.\n */\nvoid widget_resize(widget *wid, short w, short h);\n\n/**\n * @param wid The widget handle\n *\n * @returns the height of the widget.\n */\nint widget_get_height(widget *wid);\n\n/**\n * @param wid The widget handle\n *\n * @returns the width of the widget.\n */\nint widget_get_width(widget *wid);\n\n/**\n * @param wid The widget handle\n *\n * @returns the y position of the widget relative to its parent.\n */\nint widget_get_y_pos(widget *wid);\n\n/**\n * @param wid The widget handle\n *\n * @returns the x position of the widget relative to its parent.\n */\nint widget_get_x_pos(widget *wid);\n\n/**\n * @param wid The widget handle\n * @param x A pointer to the absolute X coordinates\n * @param y A pointer to the absolute Y coordinates\n *\n * Will modify param x and param y to make them relative to param wid .\n */\nvoid widget_xy_to_relative(widget *wid, gint *x, gint *y);\n\n/**\n * @param wid The widget handle\n *\n * Update the widget, and its parent recursively.\n * This should be called when size of widget changes.\n */\nvoid widget_update(widget *wid);\n/**\n * @param wid The widget handle\n *\n * Indicate that the widget needs to be redrawn.\n * This is done by setting the redraw flag on the toplevel widget.\n */\nvoid widget_queue_redraw(widget *wid);\n/**\n * @param wid The widget handle\n *\n * Check the flag indicating the widget needs to be redrawn.\n */\ngboolean widget_need_redraw(widget *wid);\n\n/**\n * @param wid The widget handle\n * @param type The type of the wanted widget\n * @param x The x coordinate of the mouse event\n * @param y The y coordinate of the mouse event\n *\n * Get the widget that should handle a mouse event.\n *\n * @returns returns the widget that should handle the mouse event.\n */\nwidget *widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y);\n\n/**\n * @param wid The widget handle\n * @param action The action to trigger\n * @param x A pointer to the x coordinate of the click\n * @param y A pointer to the y coordinate of the click\n *\n * Trigger an action on widget.\n * param x and param y are relative to param wid .\n *\n * @returns Whether the action would be handled or not\n */\nWidgetTriggerActionResult widget_check_action(widget *wid,\n                                              G_GNUC_UNUSED guint action,\n                                              G_GNUC_UNUSED gint x,\n                                              G_GNUC_UNUSED gint y);\n\n/**\n * @param wid The widget handle\n * @param action The action to trigger\n * @param x A pointer to the x coordinate of the click\n * @param y A pointer to the y coordinate of the click\n *\n * Trigger an action on widget.\n * param x and param y are relative to param wid .\n *\n * @returns Whether the action was handled or not\n */\nWidgetTriggerActionResult widget_trigger_action(widget *wid, guint action,\n                                                gint x, gint y);\n\n/**\n * @param wid The widget handle\n * @param cb The widget trigger action callback\n * @param cb_data the user data to pass to callback\n *\n * Override the widget trigger action handler on widget.\n */\nvoid widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb,\n                                       void *cb_data);\n\n/**\n * @param wid The widget handle\n * @param x The x coordinate of the mouse event\n * @param y The y coordinate of the mouse event\n *\n * Motion notify.\n *\n * @returns TRUE when handled.\n */\ngboolean widget_motion_notify(widget *wid, gint x, gint y);\n\n/**\n * @param wid The widget handle\n * @param width The Widget width to get height for\n *\n * Get the desired height of this widget recursively.\n *\n * @returns the desired height of the widget in pixels.\n */\nint widget_get_desired_height(widget *wid, const int width);\n\n/**\n * @param wid The widget handle\n * @param height The Widget height to get height for\n *\n * Get the desired width of this widget recursively.\n *\n * @returns the desired width of the widget in pixels.\n */\nint widget_get_desired_width(widget *wid, const int height);\n/**\n * @param wid The widget handle\n *\n * Get the absolute x-position on the root widget..\n *\n * @returns the absolute x-position of widget of the widget in pixels.\n */\nint widget_get_absolute_xpos(widget *wid);\n/**\n * @param wid The widget handle\n *\n * Get the absolute y-position on the root widget..\n *\n * @returns the absolute y-position of widget of the widget in pixels.\n */\nint widget_get_absolute_ypos(widget *wid);\n/**@}*/\n#endif // ROFI_WIDGET_H\n"
  },
  {
    "path": "include/xcb-dummy.h",
    "content": "#ifndef ROFI_XCB_DUMMY_H\n#define ROFI_XCB_DUMMY_H\n\n// Dummy types for xcb values shared in view interface (not used in wayland\n// mode) This header exists so that rofi can be built without xcb headers\n// present\n\ntypedef int xcb_configure_notify_event_t;\ntypedef int xcb_window_t;\ntypedef int xcb_timestamp_t;\n\n#define XCB_WINDOW_NONE 0\n\n#endif\n"
  },
  {
    "path": "include/xcb-internal.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_XCB_INTERNAL_H\n#define ROFI_XCB_INTERNAL_H\n/** Indication we accept that startup notification api is not yet frozen */\n#define SN_API_NOT_YET_FROZEN\n#include <glib.h>\n#include <libsn/sn.h>\n\n#include \"xcb.h\"\n#include <libgwater-xcb.h>\n#include <xcb/xcb.h>\n#include <xcb/xcb_ewmh.h>\n#include <xcb/xcb_keysyms.h>\n\n#include <nkutils-bindings.h>\n\n/**\n * Structure to keep xcb stuff around.\n */\nstruct _xcb_stuff {\n  GMainLoop *main_loop;\n  GWaterXcbSource *source;\n  xcb_connection_t *connection;\n#ifdef XCB_IMDKIT\n  xcb_xic_t ic;\n  xcb_xim_t *im;\n  xcb_key_symbols_t *syms;\n#endif\n  xcb_ewmh_connection_t ewmh;\n  xcb_screen_t *screen;\n  int screen_nbr;\n  SnDisplay *sndisplay;\n  SnLauncheeContext *sncontext;\n  struct _workarea *monitors;\n  struct {\n    /** Flag indicating first event */\n    uint8_t first_event;\n    /** Keyboard device id */\n    int32_t device_id;\n  } xkb;\n  xcb_timestamp_t last_timestamp;\n  NkBindingsSeat *bindings_seat;\n  uint32_t mouse_seen;\n  xcb_window_t focus_revert;\n  char *clipboard;\n};\n\n#endif\n"
  },
  {
    "path": "include/xcb.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_XCB_H\n#define ROFI_XCB_H\n\n#include <cairo.h>\n#ifdef XCB_IMDKIT\n#include <xcb-imdkit/imclient.h>\n#endif\n#include <xcb/xcb.h>\n\n/**\n * xcb data structure type declaration.\n */\ntypedef struct _xcb_stuff xcb_stuff;\n\n/**\n * Global pointer to xcb_stuff instance.\n */\nextern xcb_stuff *xcb;\n\n/**\n * @param data String to copy to clipboard.\n *\n * copies string to clipboard.\n */\nvoid xcb_stuff_set_clipboard(char *data);\n\n/**\n * Get the root window.\n *\n * @returns the root window.\n */\nxcb_window_t xcb_stuff_get_root_window(void);\n\n/**\n * @param w The xcb_window_t to read property from.\n * @param atom The property identifier\n *\n * Get text property defined by atom from window.\n * Support utf8.\n *\n * @returns a newly allocated string with the result or NULL\n */\nchar *window_get_text_prop(xcb_window_t w, xcb_atom_t atom);\n\n/**\n * @param w The xcb_window_t to set property on\n * @param prop Atom of the property to change\n * @param atoms List of atoms to change the property too\n * @param count The length of the atoms list.\n *\n * Set property on window.\n */\nvoid window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms,\n                          int count);\n\n/** For getting the atoms in an enum  */\n#define ATOM_ENUM(x) x\n/** Get the atoms as strings. */\n#define ATOM_CHAR(x) #x\n\n/** Atoms we want to pre-load */\n#define EWMH_ATOMS(X)                                                          \\\n  X(_NET_WM_WINDOW_OPACITY), X(I3_SOCKET_PATH), X(TARGETS), X(UTF8_STRING),    \\\n      X(STRING), X(CLIPBOARD), X(WM_WINDOW_ROLE), X(_XROOTPMAP_ID),            \\\n      X(_MOTIF_WM_HINTS), X(WM_TAKE_FOCUS), X(ESETROOT_PMAP_ID)\n\n/** enumeration of the atoms. */\nenum { EWMH_ATOMS(ATOM_ENUM), NUM_NETATOMS };\n/** atoms as string */\nextern const char *netatom_names[];\n/** atoms */\nextern xcb_atom_t netatoms[NUM_NETATOMS];\n\n/**\n * Depth of visual\n */\nextern xcb_depth_t *depth;\n/**\n * Visual to use for creating window\n */\nextern xcb_visualtype_t *visual;\n/**\n * Color map to use for creating window\n */\nextern xcb_colormap_t map;\n\n/**\n * Gets a surface containing the background image of the desktop.\n *\n * @returns a cairo surface with the background image of the desktop.\n */\ncairo_surface_t *x11_helper_get_bg_surface(void);\n/**\n * Gets a surface for the root window of the desktop.\n *\n * Can be used to take screenshot.\n *\n * @returns a cairo surface for the root window of the desktop.\n */\ncairo_surface_t *x11_helper_get_screenshot_surface(void);\n\n/**\n * @param window The X11 window to modify\n *\n * Set the right hints to disable the window decoration.\n * (Set MOTIF_WM_HINTS, decoration field)\n */\nvoid x11_disable_decoration(xcb_window_t window);\n\n/**\n * List of cursor types.\n */\ntypedef enum {\n  /** Default arrow cursor */\n  CURSOR_DEFAULT = 0,\n  /** Cursor denoting a clickable area */\n  CURSOR_POINTER,\n  /** Cursor denoting an input field / selectable text */\n  CURSOR_TEXT,\n  NUM_CURSORS\n} X11CursorType;\n\n/**\n * @param window\n * @param type\n *\n * Change mouse cursor\n */\nvoid x11_set_cursor(xcb_window_t window, X11CursorType type);\n\n/**\n * List of window managers that need different behaviour to functioning.\n */\ntypedef enum {\n  /** Default EWHM compatible window manager */\n  WM_EWHM = 0,\n  /** I3 Window manager */\n  WM_DO_NOT_CHANGE_CURRENT_DESKTOP = 1,\n  /** PANGO WORKSPACE NAMES */\n  WM_PANGO_WORKSPACE_NAMES = 2,\n} WindowManagerQuirk;\n\n/**\n * Indicates the current window manager.\n * This is used for work-arounds.\n */\nextern WindowManagerQuirk current_window_manager;\n\n/**\n * @param window the window the screenshot\n * @param size   Size of the thumbnail\n *\n * Creates a thumbnail of the window.\n *\n * @returns NULL if window was not found, or unmapped, otherwise returns a\n * cairo_surface.\n */\n\ncairo_surface_t *x11_helper_get_screenshot_surface_window(xcb_window_t window,\n                                                          int size);\n\n/**\n * @param surface\n * @param radius\n * @param deviation\n *\n * Blur the content of the surface with radius and deviation.\n */\nvoid cairo_image_surface_blur(cairo_surface_t *surface, int radius,\n                              double deviation);\n\n#ifdef XCB_IMDKIT\n/**\n * IME Forwarding\n */\nvoid x11_event_handler_fowarding(xcb_xim_t *im, xcb_xic_t ic,\n                                 xcb_key_press_event_t *event, void *user_data);\n#endif\n\n/**\n * Get the currently detected window manager.\n *\n * @returns NULL when non found, otherwise a string (free with g_free)\n */\nchar *x11_helper_get_window_manager(void);\n#endif\n"
  },
  {
    "path": "include/xrmoptions.h",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#ifndef ROFI_XRMOPTIONS_H\n#define ROFI_XRMOPTIONS_H\n#include \"theme.h\"\n// Big thanks to Sean Pringle for this code.\n\n/**\n * @defgroup CONFXResources XResources Configuration\n * @ingroup CONFIGURATION\n *\n * Configuration described in Xresource format. This can be loaded from the X\n * server or file.\n *\n * @defgroup CONFXServer XServer Configuration\n * @ingroup CONFXResources\n *\n * Loads the configuration directly from the X server using the XResources\n * system.\n *\n * @defgroup CONFCommandline Commandline Configuration\n * @ingroup CONFIGURATION\n *\n * Modified the configuration based on commandline arguments\n *\n * @defgroup CONFFile File Configuration\n * @ingroup CONFXResources\n *\n * Loads the configuration from a config file that uses the XResource file\n * format.\n *\n * @defgroup CONFIGURATION Configuration\n *\n * This provides rofi configuration system, supports:\n * * Compiled defaults.\n * * XResource parsing\n * * Config file parsing\n * * Commandline options.\n *\n * @{\n */\n\n/**\n *  Type of the config options.\n */\ntypedef enum {\n  /** Config option is string */\n  xrm_String = 0,\n  /** Config option is an unsigned number */\n  xrm_Number = 1,\n  /** Config option is a signed number */\n  xrm_SNumber = 2,\n  /** Config option is a boolean (true/false) value*/\n  xrm_Boolean = 3,\n  /** Config option is a character */\n  xrm_Char = 4\n} XrmOptionType;\n\n/**\n * Parse commandline options.\n * @ingroup CONFCommandline\n */\nvoid config_parse_cmd_options(void);\n\n/**\n * Free any allocated memory.\n *\n * @ingroup CONFXResources\n */\nvoid config_xresource_free(void);\n\n/**\n * @param type The type of the value\n * @param key  The key referring to this configuration option\n * @param value The value to update based [out][in]\n * @param comment Description of this configuration option\n *\n * Add option (at runtime) to the dynamic option parser.\n */\nvoid config_parser_add_option(XrmOptionType type, const char *key, void **value,\n                              const char *comment);\n\n/**\n * Print the current configuration to stdout. Uses bold/italic when printing to\n * terminal.\n */\nvoid print_options(void);\n\n/**\n * @param option The name of the option\n * @param type   String describing the type\n * @param text   Description of the option\n * @param def    Current value of the option\n * @param isatty If printed to a terminal\n *\n * Function that does the markup for printing an configuration option to stdout.\n */\nvoid print_help_msg(const char *option, const char *type, const char *text,\n                    const char *def, int isatty);\n\n/**\n * @param length the length of the returned array\n *\n * Creates an array with a strings describing each keybinding.\n *\n * @returns an array of string with length elements\n */\nchar **config_parser_return_display_help(unsigned int *length);\n\n/**\n * @brief Set config option.\n *\n * Sets both the static as  dynamic config option.\n *\n * @param p Property to set\n * @param error Error msg when not found.\n *\n * @returns true when failed to set property.\n */\ngboolean config_parse_set_property(const Property *p, char **error);\n\n/**\n * @param out The destination.\n * @param changes Only print the changed options.\n *\n * @brief Dump configuration in rasi format.\n */\nvoid config_parse_dump_config_rasi_format(FILE *out, gboolean changes);\n/** @}*/\n#endif\n"
  },
  {
    "path": "lexer/theme-lexer.l",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n%option nodefault noyywrap\n%option nostdinit\n%option nounput\n%option never-interactive\n%option bison-locations\n%option bison-bridge\n\n%{\n#include \"config.h\"\n#include \"resources.h\"\n#include <stdio.h>\n#include <glib.h>\n#include <gio/gio.h>\n#include <helper.h>\n#include <math.h>\n#include <strings.h>\n#include \"rofi.h\"\n#include \"theme.h\"\n\n#include \"theme-parser.h\"\n#include \"css-colors.h\"\n\n#define LOG_DOMAIN \"Parser\"\nint last_state = 0;\nextern int rofi_is_in_dmenu_mode;\n\ngboolean import_optional = FALSE;\n\nconst char *rasi_theme_file_extensions[] = {\".rasi\", \".rasinc\", NULL};\n/**\n * Type of Object to parse.\n */\ntypedef enum {\n    /** Parse a file */\n    PT_FILE,\n    /** Parse a string */\n    PT_STRING,\n    /** Parse a string */\n    PT_STRING_ALLOC,\n    /** Parse environment */\n    PT_ENV\n} ParseType;\n\n/**\n * Parse object\n */\ntypedef struct _ParseObject {\n    /** Type */\n    ParseType type;\n\n    /** File pointer */\n    FILE *filein;\n    char *filename;\n\n    /** Length of string  */\n    int str_len;\n    /** String */\n    const char *input_str;\n    /** For where we need to free at end. (PT_STRING_ALLOC); */\n    char *malloc_str;\n    /** Position in file */\n    YYLTYPE  location;\n} ParseObject;\n\n\nGQueue *file_queue = NULL;\nGQueue *queue = NULL;\n\nParseObject *current = NULL;\n\n\n\nstatic double rofi_theme_parse_convert_hex ( char high, char low)\n{\n    uint8_t retv = 0;\n\n    int t = g_ascii_toupper ( high );\n    t = ( t > '9')? (t-'A'+10):(t-'0');\n    retv = t<<4;\n    t = g_ascii_toupper ( low );\n    t = ( t > '9')? (t-'A'+10):(t-'0');\n    retv +=t;\n    return retv/255.0;\n}\n\n%}\n%{\n\n#define YY_INPUT(buf,result,max_size) \\\n{\\\n    if ( current == NULL ) {\\\n        result = 0;\\\n    } else {\\\n        switch ( current->type ) { \\\n            case PT_FILE:\\\n            {\\\n                errno =0; \\\n                while ( (result = (int) fread(buf, 1, max_size, current->filein))==0 && ferror(current->filein)) \\\n                { \\\n                    if ( errno != EINTR ) \\\n                    { \\\n                        fprintf(stderr, \"Failed to read input from file: %s\\n\", strerror(errno)); \\\n                        YY_FATAL_ERROR( \"input in flex scanner failed\" ); \\\n                        break; \\\n                    } \\\n                    errno=0; \\\n                    clearerr(current->filein); \\\n                } \\\n                break;\\\n            }\\\n            case PT_ENV:\\\n            case PT_STRING_ALLOC:\\\n            case PT_STRING:\\\n            {\\\n                yy_size_t len = MIN (max_size, current->str_len);\\\n                if ( len > 0 ) {\\\n                    memcpy (buf, current->input_str, len);\\\n                    current->input_str+=len;\\\n                    current->str_len-=len;\\\n                    result = len;\\\n                } else {\\\n                    result = 0;\\\n                }\\\n                break;\\\n            }\\\n        }\\\n    }\\\n}\n\n\n#define YY_USER_ACTION {\\\n    yylloc->last_column+= yyleng;\\\n}\n#define YY_LLOC_START {\\\n    yylloc->first_line = yylloc->last_line;\\\n    yylloc->first_column = yylloc->last_column;\\\n}\n%}\n\nASC     [\\x00-\\x7f]\nASCN    [\\x00-\\t\\v-\\x7f]\nASCNP1  [\\x00-\\t\\v-\\x21\\x23-\\x7f]\nASCNP2  [\\x00-\\t\\v-\\x26\\x28-\\x7f]\nU       [\\x80-\\xbf]\nU2      [\\xc2-\\xdf]\nU3      [\\xe0-\\xef]\nU4      [\\xf0-\\xf4]\n\nUONLY   {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}\n // UANY    {ASC}|{UONLY}\nUANYN   {ASCN}|{UONLY}\n\nUANYNP1   {ASCNP1}|{UONLY}\nUANYNP2   {ASCNP2}|{UONLY}\n\nWHITESPACE [[:blank:]]\nWSO        [[:blank:]]*\nWORD       [[:alnum:]-]+\nWORD_ELEMENT [[:alpha:]][[:alnum:]-]*\nWORD_ENV   [[:alpha:]_][[:alnum:]_]*\nCOLOR_NAME [[:alpha:]]+\nSTRING     \\\"{UANYN}*\\\"|\\'{UANYN}*\\'\nSTRING_LIST \\\"{UANYNP1}*\\\"|\\'{UANYNP2}*\\'\nHEX        [[:xdigit:]]\nNUMBER     [[:digit:]]+\nUNARYMIN   -\nPX         (px)\nMM         (mm)\nEM         (em)\nCH         (ch)\nPERCENT    (\\%)\n\nINHERIT    (inherit)\n\nASTERIX    \\*\n\nENV        $\\{[[:alpha:]_][[:alnum:]_]*\\}\n\nMODIFIER_ADD      \\+\nMODIFIER_MULTIPLY \\*\nMODIFIER_MIN      (min)\nMODIFIER_MAX      (max)\nMODIFIER_ROUND    (round)\nMODIFIER_FLOOR    (floor)\nMODIFIER_CEIL     (ceil)\nMODIFIER_MODULO\t  (modulo)\n\n /* Position */\nCENTER     (?i:center)\nNORTH      (?i:north)\nSOUTH      (?i:south)\nEAST       (?i:east)\nWEST       (?i:west)\n\n /* Line Style */\nNONE          (?i:none)\nBOLD          (?i:bold)\nUNDERLINE     (?i:underline)\nITALIC        (?i:italic)\nSTRIKETHROUGH (?i:strikethrough)\nUPPERCASE     (?i:uppercase)\nLOWERCASE     (?i:lowercase)\nCAPITALIZE    (?i:capitalize)\n\n/* ANGLES */\n\nANGLE_DEG  (?i:deg)\nANGLE_GRAD (?i:grad)\nANGLE_RAD  (?i:rad)\nANGLE_TURN (?i:turn)\n\n/* LINE STYLE */\nLS_DASH    (?i:dash)\nLS_SOLID   (?i:solid)\n\n/* Orientation */\n\nORIENTATION_HORI (?i:horizontal)\nORIENTATION_VERT (?i:vertical)\n\n/* Cursor */\n\nCURSOR_DEF (?i:default)\nCURSOR_PTR (?i:pointer)\nCURSOR_TXT (?i:text)\n\n /* Color schema */\nRGBA (?i:rgb[a]?)\nHWB  (?i:hwb)\nCMYK (?i:cmyk)\nHSL  (?i:hsl[a]?)\n\n/* Image type  */\nURL (?i:url?)\nLINEAR_GRADIENT (?i:linear-gradient?)\nWIDTH  (?i:width?)\nHEIGHT (?i:height?)\nBOTH   (?i:both?)\n\n\n\nTO     (?i:to?)\nRIGHT  (?i:right?)\nLEFT   (?i:left?)\nTOP    (?i:top?)\nBOTTOM (?i:bottom?)\n\nCOLOR_TRANSPARENT (?i:transparent)\n\nS_T_PARENT_LEFT  \\(\nS_T_PARENT_RIGHT \\)\nCALC    (?i:calc)\nCOMMA            ,\nFORWARD_SLASH    \\/\n\nLIST_OPEN        \\[\nLIST_CLOSE       \\]\n\nVAR_START  \"var\"\nENV_START  \"env\"\n\nCPP_COMMENT  \"//\"\nC_COMMENT_OPEN \"/*\"\n\n\nINCLUDE    \"@import\"\nOPT_INCLUDE    \"?import\"\nTHEME \"@theme\"\nDEFAULT (?i:\\\"default\\\"?)\n\nMEDIA \"@media\"\n\nCONFIGURATION (?i:configuration)\n\nMEDIA_TYPES (monitor-id|(min|max)-(width|height|aspect-ratio)|enabled)\n\nDMENU (?i:dmenu)\n\n%x INCLUDE\n%x PROPERTIES\n%x PROPERTIES_ENV\n%x PROPERTIES_VAR\n%x PROPERTIES_ENV_VAR\n%x PROPERTIES_VAR_DEFAULT\n%x PROPERTIES_ARRAY\n%x NAMESTR\n%x SECTION\n%x DEFAULTS\n/* Media section.*/\n%x MEDIA\n%x MEDIA_CONTENT\n%x MEDIA_ENV_VAR\n%x MEDIA_ENV_VAR_CONTENT\n%x MEDIA_ENV_VAR_DEFAULT\n%%\n\n%{\nYY_LLOC_START\n%}\n%{\nif ( queue == NULL ) {\n    queue = g_queue_new ( );\n    yylloc->filename = current->filename;\n    // unsure why todo this.\n    yylloc->first_line = yylloc->last_line = 1;\n    yylloc->first_column = yylloc->last_column = 1;\n}\n%}\n\n  /**\n   * General code for handling comments.\n   * Both C and C++ style comments, including nexting.\n   */\n\n<*>{CPP_COMMENT}            {\n    int c = input();\n    while ( c != 0 && c != EOF) {\n        if ( c == '\\n' ) {\n            yylloc->last_column = 1;\n            yylloc->last_line ++;\n            break;\n        }\n        yylloc->last_column++;\n        c = input();\n    }\n    YY_LLOC_START\n}\n<*>{C_COMMENT_OPEN}            {\n    int c = 0, p;\n    int nesting_depth = 1;\n    while (nesting_depth) {\n        p = c;\n        c = input();\n        switch (c) {\n        case '*': yylloc->last_column++; if ( p == '/' ) { c = 0; nesting_depth++; } break;\n        case '/': yylloc->last_column++; if ( p == '*' ) { c = 0; nesting_depth--; } break;\n        case '\\n':  {\n            yylloc->last_column = 1;\n            yylloc->last_line ++;\n            break;\n        }\n        case 0: nesting_depth = 0; break;\n        case EOF: nesting_depth = 0; break;\n        default:\n            yylloc->last_column++;\n        ;\n        }\n    }\n    YY_LLOC_START\n}\n\n    /**\n     * HANDLE INCLUDES\n     */\n<INITIAL>{INCLUDE} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    import_optional = FALSE;\n    BEGIN(INCLUDE);\n}\n<INITIAL>{OPT_INCLUDE} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    import_optional = TRUE;\n    BEGIN(INCLUDE);\n}\n<INITIAL>{THEME} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(INCLUDE);\n    return T_RESET_THEME;\n}\n    /** Skip all whitespace */\n<INCLUDE>{WHITESPACE} {}\n\n    /** Parse path. Last element in this INCLUDE */\n<INCLUDE>{DEFAULT} {\n    ParseObject *top = g_queue_peek_head ( file_queue );\n    g_assert ( top != NULL );\n    GBytes *theme_data = g_resource_lookup_data( resources_get_resource(),\n    \"/org/qtools/rofi/default.rasi\", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);\n    if (theme_data) {\n      const char *theme = g_bytes_get_data(theme_data, NULL);\n      top->location = *yylloc;\n      ParseObject *po = g_malloc0(sizeof(ParseObject));\n      po->type = PT_STRING_ALLOC;\n      po->malloc_str = g_strdup(theme);\n      po->input_str  = po->malloc_str;\n      po->str_len   = strlen(po->malloc_str)-1;\n      current = po;\n      g_queue_push_head ( file_queue, po );\n      g_bytes_unref(theme_data);\n\n      yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE ));\n      yylloc->first_line = yylloc->last_line = 1;\n      yylloc->first_column = yylloc->last_column = 1;\n      yylloc->filename = NULL;//\"default theme\";\n    }\n    // Pop out of include.\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n}\n\n<INCLUDE>{STRING} {\n    yytext[yyleng-1] = '\\0';\n    ParseObject *top = g_queue_peek_head ( file_queue );\n    g_assert ( top != NULL );\n    char *file2 = helper_get_theme_path ( &yytext[1], rasi_theme_file_extensions, top->filename );\n    char *filename = rofi_theme_parse_prepare_file ( file2 );\n    g_free ( file2 );\n    FILE *f = fopen ( filename, \"rb\" );\n    if ( f ) {\n        top->location = *yylloc;\n        ParseObject *po = g_malloc0(sizeof(ParseObject));\n        po->type = PT_FILE;\n        po->filename = filename;\n        po->filein = f;\n        current = po;\n        g_queue_push_head ( file_queue, po );\n\n        yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE ));\n        yylloc->first_line = yylloc->last_line = 1;\n        yylloc->first_column = yylloc->last_column = 1;\n        yylloc->filename = current->filename;\n    } else {\n\tif ( !import_optional ) {\n\t\tchar *str = g_markup_printf_escaped ( \"Failed to open theme: <i>%s</i>\\nError: <b>%s</b>\",\n\t\t\t\tfilename, strerror ( errno ) );\n\t\trofi_add_warning_message ( g_string_new ( str ) );\n\t\tg_free ( str );\n\t} else {\n\t\tg_warning(\"Trying to parse optional theme: '%s', Error: %s\",\n\t\t\tfilename, strerror(errno));\n\t}\n        g_free(filename);\n    }\n    // Pop out of include. */\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n}\n  /** Everythin not yet parsed is an error. */\n<INCLUDE>. {\n    return T_ERROR_INCLUDE;\n}\n\n    /**\n     * END INCLUDES\n     */\n\n\n<INITIAL>{CONFIGURATION} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(DEFAULTS);\n    return T_CONFIGURATION;\n\n}\n\n    /**\n     * Handle defaults:  * { ... }\n     */\n<INITIAL>{ASTERIX} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(DEFAULTS);\n    return T_PDEFAULTS;\n}\n    /** Skip all whitespace */\n<DEFAULTS>{WHITESPACE} {}\n<DEFAULTS>\"\\{\"   {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(SECTION);\n    return T_BOPEN;\n}\n  /** Everything not yet parsed is an error. */\n<DEFAULTS>. {\n    return T_ERROR_DEFAULTS;\n}\n\n<INITIAL>\"#\"            {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(NAMESTR);\n    return T_NAME_PREFIX;\n}\n    /* Go into parsing a section. */\n<NAMESTR>\"\\{\"                    {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(SECTION);\n    return T_BOPEN;\n}\n  /* Pop out of parsing a section. */\n<SECTION>\"\\}\"             {\n    g_queue_pop_head ( queue );\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n    return T_BCLOSE;\n}\n\n<NAMESTR>\\.|{WHITESPACE}    { return T_NSEP; }\n<NAMESTR,SECTION>,{WHITESPACE}*      { return T_SSEP; }\n /* Alias color to text-color */\n<SECTION>\"color\"            { yylval->sval = g_strdup(\"text-color\"); return T_PROP_NAME;}\n<SECTION>{WORD}   { yylval->sval = g_strdup(yytext); return T_PROP_NAME;}\n<NAMESTR>{WORD_ELEMENT}         { yylval->sval = g_strdup(yytext); return T_NAME_ELEMENT;}\n\n  /* After Namestr/Classstr we want to go to state str, then to  { */\n<INITIAL,SECTION>{WHITESPACE}+\t; // ignore all whitespace\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,PROPERTIES_ARRAY,PROPERTIES_ENV_VAR,PROPERTIES_VAR>{WHITESPACE}+\t; // ignore all whitespace\n\n<SECTION>\":\"                      { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES); return T_PSEP; }\n<PROPERTIES>\";\"                   { BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); return T_PCLOSE;}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,MEDIA_ENV_VAR_CONTENT,MEDIA_ENV_VAR_DEFAULT>(true|false)          { yylval->bval= g_strcmp0(yytext, \"true\") == 0; return T_BOOLEAN;}\n<MEDIA_CONTENT>{DMENU} { yylval->bval = rofi_is_in_dmenu_mode; return T_BOOLEAN;}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,MEDIA_CONTENT>{NUMBER}\\.{NUMBER} { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,MEDIA_CONTENT>{NUMBER}            { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,MEDIA_CONTENT>{UNARYMIN}            { return T_MIN; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{STRING}                                             { yytext[yyleng-1] = '\\0'; yylval->sval = g_strcompress(&yytext[1]); return T_STRING;}\n<PROPERTIES_ARRAY>{STRING_LIST}                                                                        { yytext[yyleng-1] = '\\0'; yylval->sval = g_strcompress(&yytext[1]); return T_STRING;}\n\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>@{WORD}               {\n    yylval->sval = g_strdup(yytext+1);\n    return T_LINK;\n}\n\n<SECTION>\"\\{\"       {\n  // Double to fit in scheme.\n  g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n  g_queue_push_head ( queue, GINT_TO_POINTER (SECTION) );\n  BEGIN(SECTION);\n  return T_BOPEN;\n}\n\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{EM}       { return T_UNIT_EM; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{CH}       { return T_UNIT_CH; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT,MEDIA_CONTENT>{PX}       { return T_UNIT_PX; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT,MEDIA_CONTENT>{MM}       { return T_UNIT_MM; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{PERCENT}  { return T_PERCENT; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{LS_SOLID} { return T_SOLID;   }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{LS_DASH}  { return T_DASH;    }\n\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{INHERIT}  { return T_INHERIT; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_ADD}       { return T_MODIFIER_ADD; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_MULTIPLY}  { return T_MODIFIER_MULTIPLY; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_MIN}  { return T_MODIFIER_MIN; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_MAX}  { return T_MODIFIER_MAX; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_ROUND}  { return T_MODIFIER_ROUND; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_FLOOR}  { return T_MODIFIER_FLOOR; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_CEIL}  { return T_MODIFIER_CEIL; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{MODIFIER_MODULO}  { return T_MODIFIER_MODULO; }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{CALC}  { return T_CALC; }\n\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_ARRAY,PROPERTIES_VAR_DEFAULT>{ENV} {\n    yytext[yyleng-1] = '\\0';\n    const char *val = g_getenv(yytext+2);\n    if ( val ) {\n        ParseObject *top = g_queue_peek_head ( file_queue );\n        top->location = *yylloc;\n        ParseObject *po = g_malloc0(sizeof(ParseObject));\n        po->type = PT_ENV;\n        po->input_str = val;\n        po->str_len = strlen(val);\n        current = po;\n        g_queue_push_head ( file_queue, po );\n\n        yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE ));\n        yylloc->first_line = yylloc->last_line = 1;\n        yylloc->first_column = yylloc->last_column = 1;\n        yylloc->filename = current->filename;\n        g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ENV);\n    }\n}\n<PROPERTIES_ENV_VAR>{WORD_ENV} {\n    const char *val = g_getenv(yytext);\n    if ( val ) {\n        ParseObject *top = g_queue_peek_head ( file_queue );\n        top->location = *yylloc;\n        ParseObject *po = g_malloc0(sizeof(ParseObject));\n        po->type = PT_ENV;\n        po->input_str = val;\n        po->str_len = strlen(val);\n        current = po;\n        g_queue_push_head ( file_queue, po );\n\n        yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE ));\n        yylloc->first_line = yylloc->last_line = 1;\n        yylloc->first_column = yylloc->last_column = 1;\n        yylloc->filename = current->filename;\n        g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES_ENV);\n    }\n}\n<MEDIA_ENV_VAR>{WORD_ENV} {\n    const char *val = g_getenv(yytext);\n    if ( val ) {\n        ParseObject *top = g_queue_peek_head ( file_queue );\n        top->location = *yylloc;\n        ParseObject *po = g_malloc0(sizeof(ParseObject));\n        po->type = PT_ENV;\n        po->input_str = val;\n        po->str_len = strlen(val);\n        current = po;\n        g_queue_push_head ( file_queue, po );\n\n        yypush_buffer_state (yy_create_buffer ( 0, YY_BUF_SIZE ));\n        yylloc->first_line = yylloc->last_line = 1;\n        yylloc->first_column = yylloc->last_column = 1;\n        yylloc->filename = current->filename;\n        g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(MEDIA_ENV_VAR_CONTENT);\n    }\n}\n\n\n /**\n  * Color parsing. It is easier to do this at lexer level.\n  * Other schemes are done at yacc level.\n  */\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>#{HEX}{8}       {\n    yylval->colorval.red   = rofi_theme_parse_convert_hex(yytext[1],yytext[2]);\n    yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[3],yytext[4]);\n    yylval->colorval.blue  = rofi_theme_parse_convert_hex(yytext[5],yytext[6]);\n    yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[7],yytext[8]);\n    return T_COLOR;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>#{HEX}{6}       {\n    yylval->colorval.alpha = 1.0;\n    yylval->colorval.red   = rofi_theme_parse_convert_hex(yytext[1],yytext[2]);\n    yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[3],yytext[4]);\n    yylval->colorval.blue  = rofi_theme_parse_convert_hex(yytext[5],yytext[6]);\n    return T_COLOR;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>#{HEX}{3}       {\n    yylval->colorval.alpha = 1.0;\n    yylval->colorval.red   = rofi_theme_parse_convert_hex(yytext[1],yytext[1]);\n    yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[2],yytext[2]);\n    yylval->colorval.blue  = rofi_theme_parse_convert_hex(yytext[3],yytext[3]);\n    return T_COLOR;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>#{HEX}{4}       {\n    yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[4],yytext[4]);\n    yylval->colorval.red   = rofi_theme_parse_convert_hex(yytext[1],yytext[1]);\n    yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[2],yytext[2]);\n    yylval->colorval.blue  = rofi_theme_parse_convert_hex(yytext[3],yytext[3]);\n    return T_COLOR;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>argb:{HEX}{8}       {\n    yylval->colorval.alpha = rofi_theme_parse_convert_hex(yytext[5],yytext[6]);\n    yylval->colorval.red   = rofi_theme_parse_convert_hex(yytext[7],yytext[8]);\n    yylval->colorval.green = rofi_theme_parse_convert_hex(yytext[9],yytext[10]);\n    yylval->colorval.blue  = rofi_theme_parse_convert_hex(yytext[11],yytext[12]);\n    return T_COLOR;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>argb:{HEX}{7}       {\n    return T_ERROR_ARGB_SPEC;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{URL}             { return T_URL;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{LINEAR_GRADIENT} { return T_LINEAR_GRADIENT;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{WIDTH}           { return T_WIDTH;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{HEIGHT}          { return T_HEIGHT;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{BOTH}            { return T_BOTH;       }\n\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{TO}              { return T_TO;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{LEFT}            { return T_LEFT;     }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{RIGHT}           { return T_RIGHT;    }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{TOP}             { return T_TOP;      }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{BOTTOM}          { return T_BOTTOM;   }\n\n /* Color schemes */\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{RGBA}             { return T_COL_RGBA;       }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{HSL}              { return T_COL_HSL;        }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{HWB}              { return T_COL_HWB;        }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CMYK}             { return T_COL_CMYK;       }\n\n<PROPERTIES_ENV_VAR,MEDIA_ENV_VAR,PROPERTIES_VAR>{S_T_PARENT_LEFT} {\n    return T_PARENT_LEFT;\n}\n /* Fluff */\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{VAR_START} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(PROPERTIES_VAR);\n    return T_VAR_START;\n}\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ENV_START} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(PROPERTIES_ENV_VAR);\n    return T_ENV_START;\n}\n<MEDIA_CONTENT>{ENV_START} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(MEDIA_ENV_VAR);\n    return T_ENV_START;\n}\n<PROPERTIES_VAR,MEDIA_ENV_VAR,PROPERTIES_ENV_VAR>{S_T_PARENT_RIGHT} {\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n    return T_PARENT_RIGHT;\n}\n<PROPERTIES_VAR,PROPERTIES_ENV_VAR>{COMMA} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(PROPERTIES_VAR_DEFAULT);\n    return T_COMMA;\n}\n<MEDIA_ENV_VAR>{COMMA} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(MEDIA_ENV_VAR_DEFAULT);\n    return T_COMMA;\n}\n<MEDIA_ENV_VAR_DEFAULT,PROPERTIES_VAR_DEFAULT>{S_T_PARENT_RIGHT} {\n    // Pop 2.\n    g_queue_pop_head ( queue );\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n    return T_PARENT_RIGHT;\n}\n<PROPERTIES_ARRAY,PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{S_T_PARENT_LEFT}  { return T_PARENT_LEFT;    }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{S_T_PARENT_RIGHT} { return T_PARENT_RIGHT;   }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{COMMA}            { return T_COMMA;          }\n<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{LIST_OPEN}        {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(PROPERTIES_ARRAY);\n    return T_LIST_OPEN;\n}\n<PROPERTIES_ARRAY>{LIST_CLOSE}       {\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n    return T_LIST_CLOSE;\n}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{FORWARD_SLASH}    { return T_FORWARD_SLASH;  }\n /* Position */\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CENTER}           { return T_POS_CENTER;     }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{EAST}             { return T_POS_EAST;       }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{WEST}             { return T_POS_WEST;       }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{SOUTH}            { return T_POS_SOUTH;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{NORTH}            { return T_POS_NORTH;      }\n /* Highlight style */\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{NONE}             { return T_NONE;           }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{BOLD}             { return T_BOLD;           }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ITALIC}           { return T_ITALIC;         }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{UNDERLINE}        { return T_UNDERLINE;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{STRIKETHROUGH}    { return T_STRIKETHROUGH;  }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{UPPERCASE}        { return T_UPPERCASE;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{LOWERCASE}        { return T_LOWERCASE;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CAPITALIZE}        { return T_CAPITALIZE;      }\n\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ANGLE_DEG}        { return T_ANGLE_DEG;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ANGLE_RAD}        { return T_ANGLE_RAD;      }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ANGLE_GRAD}       { return T_ANGLE_GRAD;     }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ANGLE_TURN}       { return T_ANGLE_TURN;     }\n\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ORIENTATION_HORI} { return ORIENTATION_HORI; }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ORIENTATION_VERT} { return ORIENTATION_VERT; }\n\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_DEF} { return CURSOR_DEF; }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_PTR} { return CURSOR_PTR; }\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_TXT} { return CURSOR_TXT; }\n\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{COLOR_TRANSPARENT} {\n    return T_COLOR_TRANSPARENT;\n}\n<PROPERTIES,PROPERTIES_ARRAY,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{COLOR_NAME} {\n    for ( unsigned int iter = 0; iter < num_CSSColors; iter++) {\n        if ( strcasecmp(yytext, CSSColors[iter].name )== 0 ) {\n            yylval->colorval.alpha = 1.0;\n            yylval->colorval.red   = CSSColors[iter].r/255.0;\n            yylval->colorval.green = CSSColors[iter].g/255.0;\n            yylval->colorval.blue  = CSSColors[iter].b/255.0;\n            return T_COLOR_NAME;\n        }\n    }\n    REJECT;\n}\n\n<INITIAL,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT,MEDIA_ENV_VAR_CONTENT><<EOF>>  {\n    ParseObject *po = g_queue_pop_head ( file_queue );\n    if ( po ) {\n        if ( po->type == PT_FILE ) {\n            fclose ( po->filein );\n        }\n        if ( po->type == PT_STRING_ALLOC ) {\n          g_free( po->malloc_str);\n        }\n        g_free ( po->filename );\n        g_free ( po );\n    }\n    po = g_queue_peek_head ( file_queue );\n    if ( po == NULL ) {\n        g_queue_free ( queue );\n        // Reset pointer to NULL\n        queue = NULL;\n        yyterminate();\n    } else {\n        yypop_buffer_state();\n        current = po;\n        *yylloc = current->location;\n        BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue )));\n    }\n}\n\n<*>\\n {\n        yylloc->last_column = 1;\n        yylloc->last_line ++;\n};\n<*>(\\r\\n) {\n        yylloc->last_column = 1;\n        yylloc->last_line ++;\n};\n\n\n<INITIAL>{MEDIA} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(MEDIA);\n    return T_MEDIA;\n}\n<INITIAL>\"\\}\" {\n    g_queue_pop_head ( queue );\n    BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));\n    return T_BCLOSE;\n}\n\n<MEDIA>{S_T_PARENT_LEFT} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(MEDIA_CONTENT);\n    return T_PARENT_LEFT;\n}\n<MEDIA_CONTENT>{MEDIA_TYPES} {\n    yylval->sval = g_strdup(yytext);\n    return T_MEDIA_TYPE;\n}\n<MEDIA_CONTENT>\":\" {\n    return T_PSEP;\n}\n<MEDIA_CONTENT>{S_T_PARENT_RIGHT} {\n    int  id = GPOINTER_TO_INT(g_queue_pop_head ( queue ));\n    BEGIN(id);\n    return T_PARENT_RIGHT;\n}\n<MEDIA>\"\\{\" {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(INITIAL);\n    return T_BOPEN;\n}\n\n\n /**\n  * Media defaults.\n  */\n<MEDIA,MEDIA_CONTENT,MEDIA_ENV_VAR,MEDIA_ENV_VAR_DEFAULT,MEDIA_ENV_VAR_CONTENT>{WHITESPACE}+\t; // ignore all whitespace\n\n<MEDIA,MEDIA_CONTENT,MEDIA_ENV_VAR,MEDIA_ENV_VAR_DEFAULT,MEDIA_ENV_VAR_CONTENT>. {\n    yytext[yyleng-1] = '\\0';\n    return T_ERROR;\n}\n\n /**\n  * If we just encounter a word, we assume it is a Widget name.\n  * This makes include,theme, configuration a reserved keyword.\n  */\n<INITIAL>{WORD_ELEMENT} {\n    g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );\n    BEGIN(NAMESTR);\n    yylval->sval = g_strdup(yytext);\n    return T_NAME_ELEMENT;\n}\n<INITIAL>. {\n    yytext[yyleng-1] = '\\0';\n    return T_ERROR;\n}\n<SECTION>. {\n    yytext[yyleng-1] = '\\0';\n    return T_ERROR_SECTION;\n}\n<PROPERTIES_ARRAY,PROPERTIES_VAR>{WORD_ELEMENT} {\n    yylval->sval = g_strdup(yytext);\n    return T_ELEMENT;\n}\n\n<MEDIA_ENV_VAR,PROPERTIES_ENV_VAR,PROPERTIES_VAR,PROPERTIES_ARRAY,PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>. {\n    yytext[yyleng-1] = '\\0';\n    return T_ERROR_PROPERTY;\n}\n<NAMESTR>. {\n    yytext[yyleng-1] = '\\0';\n    return T_ERROR_NAMESTRING;\n}\n%%\n\n\ngboolean rofi_theme_parse_file ( const char *file )\n{\n    char *file2 = helper_get_theme_path ( file, rasi_theme_file_extensions, NULL );\n    char *filename = rofi_theme_parse_prepare_file ( file2 );\n    g_free ( file2 );\n\n    yyin = fopen ( filename, \"rb\" );\n    if ( yyin == NULL ) {\n        char *str = g_markup_printf_escaped ( \"Failed to open theme: <i>%s</i>\\nError: <b>%s</b>\",\n                filename, strerror ( errno ) );\n        rofi_add_error_message ( g_string_new ( str ) );\n        g_free ( str );\n        g_free ( filename );\n        return TRUE;\n    }\n\n    /** Add Parse object */\n    file_queue = g_queue_new ();\n    ParseObject *po = g_malloc0(sizeof(ParseObject));\n    po->type = PT_FILE;\n    po->filename = filename;\n    po->filein = yyin;\n    current = po;\n    g_queue_push_head ( file_queue, po );\n    g_debug ( \"Parsing top file: '%s'\", filename );\n\n    int parser_retv = yyparse ( file );\n    yylex_destroy ();\n    yyin = NULL;\n\n    while ( (po = g_queue_pop_head ( file_queue ) )) {\n      if ( po->type == PT_FILE ) {\n        fclose ( po->filein );\n      }\n      if ( po->type == PT_STRING_ALLOC ) {\n        g_free( po->malloc_str);\n      }\n      g_free ( po->filename );\n      g_free ( po );\n    }\n    // Free up.\n    g_queue_free ( file_queue );\n    file_queue = NULL;\n    if ( parser_retv != 0 ) {\n        return TRUE;\n    }\n    return FALSE;\n}\ngboolean rofi_theme_parse_string ( const char *string )\n{\n    yyin      = NULL;\n\n    /** Add Parse object */\n    file_queue = g_queue_new ();\n    ParseObject *po = g_malloc0(sizeof(ParseObject));\n    po->type = PT_STRING;\n    po->input_str = string;\n    po->str_len   = strlen(string);\n    current = po;\n    g_queue_push_head ( file_queue, po );\n    g_debug ( \"Parsing string: '%s'\", string );\n\n    int parser_retv = yyparse ( string );\n    yylex_destroy ();\n\n    while ( (po = g_queue_pop_head ( file_queue ) )) {\n      if ( po->type == PT_FILE ) {\n        fclose ( po->filein );\n      }\n      if ( po->type == PT_STRING_ALLOC ) {\n        g_free( po->malloc_str);\n      }\n      g_free ( po->filename );\n      g_free ( po );\n    }\n    // Free up.\n    g_queue_free ( file_queue );\n    file_queue = NULL;\n    if ( parser_retv != 0 ) {\n        return TRUE;\n    }\n    return FALSE;\n}\n"
  },
  {
    "path": "lexer/theme-parser.y",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n%define api.pure\n%define parse.error verbose\n%locations\n%glr-parser\n%skeleton \"glr.c\"\n%parse-param {const char *what}\n%code requires {\n#include \"theme.h\"\n#include \"xrmoptions.h\"\n#include \"css-colors.h\"\n#include \"rofi.h\"\n\ntypedef struct YYLTYPE {\n  int first_line;\n  int first_column;\n  int last_line;\n  int last_column;\n  char *filename;\n} YYLTYPE;\n# define YYLTYPE_IS_DECLARED 1 /* alert the parser that we have our own definition */\n\n# define YYLLOC_DEFAULT(Current, Rhs, N)                               \\\n    do                                                                 \\\n      if (N)                                                           \\\n        {                                                              \\\n          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;       \\\n          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;     \\\n          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;        \\\n          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;      \\\n          (Current).filename     = YYRHSLOC (Rhs, 1).filename;         \\\n        }                                                              \\\n      else                                                             \\\n        { /* empty RHS */                                              \\\n          (Current).first_line   = (Current).last_line   =             \\\n            YYRHSLOC (Rhs, 0).last_line;                               \\\n          (Current).first_column = (Current).last_column =             \\\n            YYRHSLOC (Rhs, 0).last_column;                             \\\n          (Current).filename  = NULL;                        /* new */ \\\n        }                                                              \\\n    while (0)\n}\n%{\n#include \"config.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <glib.h>\n\n#include \"theme-parser.h\"\nThemeWidget *rofi_theme = NULL;\nvoid yyerror(YYLTYPE *yylloc, const char *what, const char* s);\nint yylex (YYSTYPE *, YYLTYPE *);\n\n\nstatic int check_in_range ( double index, double low, double high, YYLTYPE *loc )\n{\n    if ( index > high || index < low ) {\n        gchar *str = g_strdup_printf(\"Value out of range: \\n\\t\\tValue: X = %.2lf;\\n\\t\\tRange: %.2lf <= X <= %.2lf.\", index, low, high );\n        yyerror ( loc, loc->filename, str);\n        g_free(str);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nstatic double hue2rgb ( double p, double q, double t )\n{\n    t += (t<0)?1.0:0.0;\n    t -= (t>1)?1.0:0.0;\n    if ( t < (1/6.0) ) {\n         return p + (q - p) * 6 * t;\n    }\n    if ( t < (1/2.0) ) {\n         return q;\n    }\n    if ( t < (2/3.0) ) {\n        return p + (q - p) * (2/3.0 - t) * 6;\n    }\n    return p;\n}\nstatic ThemeColor hsl_to_rgb ( double h, double s, double l )\n{\n    ThemeColor colour;\n    colour.alpha = 1.0;\n\n    if (s < 0.001 && s > -0.001) {\n        colour.red = colour.green = colour.blue = l; // achromatic\n    } else {\n\n        double q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n        double p = 2 * l - q;\n        colour.red   = hue2rgb(p, q, h + 1/3.0);\n        colour.green = hue2rgb(p, q, h);\n        colour.blue  = hue2rgb(p, q, h - 1/3.0);\n    }\n\n    return colour;\n}\nstatic ThemeColor hwb_to_rgb ( double h, double w, double b )\n{\n    ThemeColor retv = hsl_to_rgb ( h, 1.0, 0.5);\n    retv.red   *= ( 1. - w - b );\n    retv.red   += w;\n    retv.green *= ( 1. - w - b );\n    retv.green += w;\n    retv.blue  *= ( 1. - w - b );\n    retv.blue += w;\n    return retv;\n}\n%}\n\n%union {\n    int           ival;\n    double        fval;\n    char          *sval;\n    char          cval;\n    int           bval;\n    WindowLocation wloc;\n    ThemeColor    colorval;\n    ThemeWidget   *theme;\n    GList         *list;\n    Property      *property;\n    GHashTable    *property_list;\n    RofiDistance      distance;\n    RofiDistanceUnit  *distance_unit;\n}\n\n%token <ival>     T_END              0  \"end of file\"\n%token <ival>     T_ERROR            1  \"error from file parser\"\n%token <ival>     T_ERROR_PROPERTY   2  \"invalid property value\"\n%token <ival>     T_ERROR_SECTION    3  \"invalid property name\"\n%token <ival>     T_ERROR_NAMESTRING 4  \"invalid element name\"\n%token <ival>     T_ERROR_DEFAULTS   5  \"invalid defaults name\"\n%token <ival>     T_ERROR_INCLUDE    6  \"invalid import value\"\n%token <ival>     T_ERROR_ARGB_SPEC  7  \"invalid argb color. Requires 8 (not 7) elements: argb:AARRGGBB.\"\n%token <ival>     T_INT                 \"Integer number\"\n%token <fval>     T_DOUBLE              \"Floating-point number\"\n%token <sval>     T_STRING              \"UTF-8 encode string\"\n%token <sval>     T_MEDIA_TYPE          \"Media type\"\n%token <sval>     T_PROP_NAME           \"property name\"\n%token <colorval> T_COLOR_NAME          \"Color value by name\"\n%token <sval>     T_NAME_ELEMENT        \"Element name\"\n%token <bval>     T_BOOLEAN             \"Boolean value (true or false)\"\n%token <colorval> T_COLOR               \"Hexidecimal color value\"\n%token <sval>     T_LINK                \"Reference\"\n%token <sval>     T_ELEMENT             \"Name of element\"\n%token T_POS_CENTER                     \"Center\"\n%token T_POS_EAST                       \"East\"\n%token T_POS_WEST                       \"West\"\n%token T_POS_NORTH                      \"North\"\n%token T_POS_SOUTH                      \"South\"\n\n%token T_MEDIA                          \"@media\"\n\n%token T_NONE                           \"None\"\n%token T_BOLD                           \"Bold\"\n%token T_ITALIC                         \"Italic\"\n%token T_UNDERLINE                      \"Underline\"\n%token T_STRIKETHROUGH                  \"Strikethrough\"\n%token T_DASH                           \"Dash\"\n%token T_SOLID                          \"Solid\"\n%token T_UPPERCASE                      \"Uppercase\"\n%token T_CAPITALIZE                     \"Capitalize\"\n%token T_LOWERCASE                      \"Lowercase\"\n\n%token T_UNIT_PX                        \"pixels\"\n%token T_UNIT_MM                        \"mm\"\n%token T_UNIT_EM                        \"em\"\n%token T_UNIT_CH                        \"ch\"\n\n%token T_ANGLE_DEG                      \"Degrees\"\n%token T_ANGLE_GRAD                     \"Gradians\"\n%token T_ANGLE_RAD                      \"Radians\"\n%token T_ANGLE_TURN                     \"Turns\"\n\n%token ORIENTATION_HORI                 \"Horizontal\"\n%token ORIENTATION_VERT                 \"Vertical\"\n\n%token CURSOR_DEF                       \"Default\"\n%token CURSOR_PTR                       \"Pointer\"\n%token CURSOR_TXT                       \"Text\"\n\n%token T_COL_RGBA                       \"rgb[a] colorscheme\"\n%token T_COL_HSL                        \"hsl colorscheme\"\n%token T_COL_HWB                        \"hwb colorscheme\"\n%token T_COL_CMYK                       \"cmyk colorscheme\"\n\n%token T_URL                            \"an URL\"\n%token T_WIDTH                          \"an WIDTH\"\n%token T_HEIGHT                         \"an HEIGHT\"\n%token T_BOTH                           \"an BOTH\"\n%token T_TO                             \"an TO\"\n%token T_LEFT                           \"an LEFT\"\n%token T_RIGHT                          \"an RIGHT\"\n%token T_TOP                            \"an TOP\"\n%token T_BOTTOM                         \"an BOTTOM\"\n\n%type <ival>                            t_property_direction\n%type <ival>                            t_property_scale_type\n%token T_LINEAR_GRADIENT                \"a linear gradient\"\n\n%token T_PARENT_LEFT                    \"Parent left ('(')\"\n%token T_PARENT_RIGHT                   \"Parent right (')')\"\n%token T_COMMA                          \"comma separator (',')\"\n%token T_FORWARD_SLASH                  \"forward slash ('/')\"\n%token T_PERCENT                        \"Percent sign ('%')\"\n\n%token T_LIST_OPEN                      \"List open ('[')\"\n%token T_LIST_CLOSE                     \"List close (']')\"\n\n%token T_MODIFIER_ADD                   \"Add ('+')\"\n%token T_MODIFIER_MULTIPLY              \"Multiply ('*')\"\n%token T_MODIFIER_MODULO                \"Modulo ('modulo')\"\n\n%token T_MODIFIER_MAX                   \"Max ('max')\"\n%token T_MODIFIER_MIN                   \"Min ('min')\"\n%token T_MODIFIER_ROUND                 \"Min ('round')\"\n%token T_MODIFIER_FLOOR                 \"Min ('floor')\"\n%token T_MODIFIER_CEIL                  \"Min ('ceil')\"\n\n%token T_CALC                           \"calc\"\n\n%token T_BOPEN                          \"bracket open ('{')\"\n%token T_BCLOSE                         \"bracket close ('}')\"\n%token T_PSEP                           \"property separator (':')\"\n%token T_PCLOSE                         \"property close (';')\"\n%token T_NSEP                           \"Name separator (' ' or '.')\"\n%token T_SSEP                           \"Selector separator (',')\"\n%token T_NAME_PREFIX                    \"Element section ('# {name} { ... }')\"\n%token T_PDEFAULTS                      \"Default settings section ( '* { ... }')\"\n%token T_CONFIGURATION                  \"Configuration block\"\n%token T_RESET_THEME                    \"Reset Theme\"\n\n%token T_COLOR_TRANSPARENT              \"Transparent\"\n\n%token T_INHERIT                        \"Inherit\"\n\n%token T_MIN\t\t\t\t\"-\"\n\n\n%token T_VAR_START                      \"var\" \n%token T_ENV_START                      \"env\" \n\n%type <theme>          t_entry_list\n%type <theme>          t_entry_list_included\n%type <list>           t_entry_name_path\n%type <list>           t_property_name_list\n%type <list>           t_entry_name_path_selectors\n%type <list>           t_color_list\n%type <property>       t_property\n%type <property>       t_property_element\n%type <property_list>  t_property_list\n%type <property_list>  t_property_list_optional\n%type <colorval>       t_property_color\n%type <fval>           t_property_color_value\n%type <fval>           t_property_color_opt_alpha_c\n%type <fval>           t_property_color_opt_alpha_ws\n%type <fval>           t_property_color_value_unit\n%type <fval>           t_property_color_value_angle\n%type <sval>           t_property_name\n%type <distance>       t_property_distance\n%type <distance>       t_property_distance_zero\n%type <distance_unit>  t_property_distance_unit_math\n%type <distance_unit>  t_property_distance_unit_math2\n%type <distance_unit>  t_property_distance_unit_math3\n%type <distance_unit>  t_property_distance_unit\n%type <ival>           t_property_unit\n%type <wloc>           t_property_position\n%type <wloc>           t_property_position_ew\n%type <wloc>           t_property_position_sn\n%type <ival>           t_property_highlight_styles\n%type <ival>           t_property_highlight_style\n%type <ival>           t_property_line_style\n%type <list>           t_property_element_list\n%type <list>           t_property_element_list_optional\n%type <ival>           t_property_orientation\n%type <ival>           t_property_cursor\n%type <ival>           t_name_prefix_optional\n%type  <fval>          t_property_number\n%start t_main\n\n%%\n\n/**\n * First have the configuration blocks, then the theme.\n */\nt_main\n: t_entry_list_included {\n    // Dummy at this point.\n    if ( rofi_theme == NULL ) {\n      rofi_theme_reset();\n    }\n\n    rofi_theme_widget_add_properties ( rofi_theme, $1->properties );\n    for ( unsigned int i = 0; i < $1->num_widgets; i++ ) {\n        ThemeWidget *d = $1->widgets[i];\n        rofi_theme_parse_merge_widgets(rofi_theme, d);\n    }\n    rofi_theme_free ( $1 );\n}\n;\n\n/**\n * Small dummy object to make the prefix optional.\n */\nt_name_prefix_optional\n: T_NAME_PREFIX {}\n| %empty {}\n;\n\nt_entry_list_included:\nt_entry_list {\n  $$ =$1;\n}\n| t_entry_list_included T_RESET_THEME t_entry_list {\n\n    rofi_theme_reset();\n    rofi_theme_free($1);\n    $$ = $3;\n}\n\n\nt_entry_list:\nt_entry_list T_CONFIGURATION T_BOPEN t_config_property_list_optional T_BCLOSE {\n  $$ = $1;\n}\n|%empty {\n    $$ = g_slice_new0 ( ThemeWidget );\n    if ( rofi_configuration == NULL ) {\n      rofi_configuration       = g_slice_new0 ( ThemeWidget );\n      rofi_configuration->name = g_strdup ( \"Root\" );\n    }\n  }\n|  t_entry_list t_name_prefix_optional t_entry_name_path_selectors T_BOPEN t_property_list_optional T_BCLOSE\n{\n    for ( GList *liter = g_list_first ( $3); liter; liter = g_list_next ( liter ) ) {\n        ThemeWidget *wid = $1;\n        for ( GList *iter = g_list_first ( (GList*)liter->data ); wid && iter ; iter = g_list_next ( iter ) ) {\n            wid = rofi_theme_find_or_create_name ( wid, iter->data );\n        }\n        g_list_free_full ( (GList*)liter->data, g_free );\n        wid->set = TRUE;\n        rofi_theme_widget_add_properties ( wid, $5);\n    }\n    if ( $5 ) {\n        g_hash_table_destroy ( $5 );\n    }\n    g_list_free ( $3 );\n}\n| t_entry_list T_PDEFAULTS T_BOPEN t_property_list_optional T_BCLOSE {\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, \"*\" );\n    rofi_theme_widget_add_properties (wid, $4);\n    if ( $4 ) {\n        g_hash_table_destroy ( $4 );\n    }\n}\n| t_entry_list T_MEDIA T_PARENT_LEFT T_MEDIA_TYPE T_PSEP t_property_number T_PARENT_RIGHT T_BOPEN t_entry_list T_BCLOSE {\n    gchar *name = g_strdup_printf(\"@media ( %s: %f )\",$4, $6);\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, name );\n    wid->set = TRUE;\n    wid->media = g_slice_new0(ThemeMedia);\n    wid->media->type = rofi_theme_parse_media_type ( $4 );\n    wid->media->value = $6;\n    for ( unsigned int i = 0; i < $9->num_widgets; i++ ) {\n        ThemeWidget *d = $9->widgets[i];\n        rofi_theme_parse_merge_widgets(wid, d);\n    }\n    g_free ( $4 );\n    g_free ( name );\n}\n| t_entry_list T_MEDIA T_PARENT_LEFT T_MEDIA_TYPE T_PSEP T_INT T_UNIT_PX T_PARENT_RIGHT T_BOPEN t_entry_list T_BCLOSE {\n    gchar *name = g_strdup_printf(\"@media ( %s: %d px )\",$4, $6);\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, name );\n    wid->set = TRUE;\n    wid->media = g_slice_new0(ThemeMedia);\n    wid->media->type = rofi_theme_parse_media_type ( $4 );\n    wid->media->value = (double)$6;\n    for ( unsigned int i = 0; i < $10->num_widgets; i++ ) {\n        ThemeWidget *d = $10->widgets[i];\n        rofi_theme_parse_merge_widgets(wid, d);\n    }\n    g_free ( $4 );\n    g_free ( name );\n}\n| t_entry_list T_MEDIA T_PARENT_LEFT T_MEDIA_TYPE T_PSEP T_BOOLEAN T_PARENT_RIGHT T_BOPEN t_entry_list T_BCLOSE {\n    gchar *name = g_strdup_printf(\"@media ( %s: %s )\",$4, $6?\"true\":\"false\");\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, name );\n    wid->set = TRUE;\n    wid->media = g_slice_new0(ThemeMedia);\n    wid->media->type = rofi_theme_parse_media_type ( $4 );\n    wid->media->boolv = $6;\n    for ( unsigned int i = 0; i < $9->num_widgets; i++ ) {\n        ThemeWidget *d = $9->widgets[i];\n        rofi_theme_parse_merge_widgets(wid, d);\n    }\n    g_free ( $4 );\n    g_free ( name );\n}\n| t_entry_list T_MEDIA T_PARENT_LEFT T_MEDIA_TYPE T_PSEP T_ENV_START T_PARENT_LEFT T_BOOLEAN T_COMMA T_BOOLEAN T_PARENT_RIGHT T_PARENT_RIGHT T_BOPEN t_entry_list T_BCLOSE {\n    gchar *name = g_strdup_printf(\"@media ( %s: %s )\",$4, $8?\"true\":\"false\");\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, name );\n    wid->set = TRUE;\n    wid->media = g_slice_new0(ThemeMedia);\n    wid->media->type = rofi_theme_parse_media_type ( $4 );\n    wid->media->boolv = $8;\n    for ( unsigned int i = 0; i < $14->num_widgets; i++ ) {\n        ThemeWidget *d = $14->widgets[i];\n        rofi_theme_parse_merge_widgets(wid, d);\n    }\n    g_free ( $4 );\n    g_free ( name );\n}\n| t_entry_list T_MEDIA T_PARENT_LEFT T_MEDIA_TYPE T_PSEP T_ENV_START T_PARENT_LEFT T_COMMA T_BOOLEAN T_PARENT_RIGHT T_PARENT_RIGHT T_BOPEN t_entry_list T_BCLOSE {\n    gchar *name = g_strdup_printf(\"@media ( %s: %s )\",$4, $9?\"true\":\"false\");\n    ThemeWidget *wid = rofi_theme_find_or_create_name ( $1, name );\n    wid->set = TRUE;\n    wid->media = g_slice_new0(ThemeMedia);\n    wid->media->type = rofi_theme_parse_media_type ( $4 );\n    wid->media->boolv = $9;\n    for ( unsigned int i = 0; i < $13->num_widgets; i++ ) {\n        ThemeWidget *d = $13->widgets[i];\n        rofi_theme_parse_merge_widgets(wid, d);\n    }\n    g_free ( $4 );\n    g_free ( name );\n}\n;\n\nt_config_property_list_optional\n: %empty {}\n| t_config_property_list\n;\n\nt_config_property_list\n: t_config_property {\n}\n| t_config_property_list  t_config_property  {\n};\n\nt_config_property\n: t_property {\n    char *error = NULL;\n    if ( config_parse_set_property ( $1, &error ) ) {\n        // TODO Generate error.\n#ifdef FATAL_CONFIG_ERROR\n        yyerror ( &(@$), @$.filename, error );\n#else\n        g_warning(\"%s:%d:%d: %s\\n\", @$.filename, @$.first_line, @$.first_column, error);\n        GString *str = g_string_new(\"\");\n        g_string_append_printf(str,\"%s:%d:%d: %s\\n\", @$.filename, @$.first_line, @$.first_column, error);\n        rofi_add_error_message(str);\n#endif\n        g_free(error);\n    }\n    // We don't keep any reference to this after this point, so the property can be free'ed.\n    rofi_theme_property_free ( $1 );\n}\n|  t_property_name_list T_BOPEN t_property_list_optional T_BCLOSE\n{\n  \n  for ( GList *iter = g_list_first( $1) ; iter; iter = g_list_next(iter)){\n    ThemeWidget *wid = rofi_configuration;\n    wid = rofi_theme_find_or_create_name ( wid, iter->data );\n    wid->set = TRUE;\n    rofi_theme_widget_add_properties ( wid, $3);\n  }\n  if ( $3 ) {\n    g_hash_table_destroy ( $3 );\n  }\n  g_list_free_full ( $1, g_free );\n}\n;\n\n/**\n * properties\n */\nt_property_list_optional\n          : %empty { $$ = NULL; }\n          | t_property_list { $$ = $1; }\n;\n\nt_property_list:\n  t_property {\n    $$ = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify)rofi_theme_property_free );\n    g_hash_table_replace ( $$, $1->name, $1 );\n  }\n| t_property_list t_property {\n    // Old will be free'ed, and key/value will be replaced.\n    g_hash_table_replace ( $$, $2->name, $2 );\n  }\n;\n\nt_property\n: t_property_name T_PSEP t_property_element T_PCLOSE {\n    $$ = $3;\n    $$->name = $1;\n   }\n|   t_property_name T_PSEP T_VAR_START T_PARENT_LEFT T_ELEMENT T_PARENT_RIGHT T_PCLOSE{\n        $$ = rofi_theme_property_create ( P_LINK );\n        $$->name = $1;\n        $$->value.link.name = $5;\n    }\n|   t_property_name T_PSEP T_VAR_START T_PARENT_LEFT T_ELEMENT T_COMMA t_property_element T_PARENT_RIGHT T_PCLOSE{\n        $$ = rofi_theme_property_create ( P_LINK );\n        $$->name = $1;\n        $$->value.link.name = $5;\n        $$->value.link.def_value = $7;\n    }\n| t_property_name T_PSEP T_ENV_START T_PARENT_LEFT T_COMMA t_property_element T_PARENT_RIGHT T_PCLOSE {\n  $$ = $6;\n  $$->name = $1;\n}\n| t_property_name T_PSEP T_ENV_START T_PARENT_LEFT t_property_element T_COMMA t_property_element T_PARENT_RIGHT T_PCLOSE {\n  $$ = $5;\n  $$->name = $1;\n}\n\nt_property_element\n:   T_INHERIT {\n        $$ = rofi_theme_property_create ( P_INHERIT );\n    }\n|   T_INT {\n        $$ = rofi_theme_property_create ( P_INTEGER );\n        $$->value.i = $1;\n    }\n|   T_DOUBLE {\n        $$ = rofi_theme_property_create ( P_DOUBLE );\n        $$->value.f = $1;\n    }\n|   T_MIN T_INT {\n        $$ = rofi_theme_property_create ( P_INTEGER );\n        $$->value.i = -$2;\n    }\n|   T_MIN T_DOUBLE {\n        $$ = rofi_theme_property_create ( P_DOUBLE );\n        $$->value.f = -$2;\n    }\n|   T_STRING {\n        $$ = rofi_theme_property_create ( P_STRING );\n        $$->value.s = $1;\n    }\n|   T_LINK {\n        $$ = rofi_theme_property_create ( P_LINK );\n        $$->value.link.name = $1;\n    }\n|   T_BOOLEAN {\n        $$ = rofi_theme_property_create ( P_BOOLEAN );\n        $$->value.b = $1;\n    }\n|  t_property_distance {\n        $$ = rofi_theme_property_create ( P_PADDING );\n        $$->value.padding = (RofiPadding){ $1, rofi_theme_property_copy_distance($1), rofi_theme_property_copy_distance($1), rofi_theme_property_copy_distance($1) };\n}\n|  t_property_distance_zero t_property_distance_zero {\n        $$ = rofi_theme_property_create ( P_PADDING );\n        $$->value.padding = (RofiPadding){ $1, $2, rofi_theme_property_copy_distance($1), rofi_theme_property_copy_distance($2) };\n}\n|  t_property_distance_zero t_property_distance_zero t_property_distance_zero {\n        $$ = rofi_theme_property_create ( P_PADDING );\n        $$->value.padding = (RofiPadding){ $1, $2, $3, rofi_theme_property_copy_distance($2) };\n}\n|  t_property_distance_zero t_property_distance_zero t_property_distance_zero t_property_distance_zero {\n        $$ = rofi_theme_property_create ( P_PADDING );\n        $$->value.padding = (RofiPadding){ $1, $2, $3, $4 };\n}\n| t_property_position {\n        $$ = rofi_theme_property_create ( P_POSITION );\n        $$->value.i = $1;\n}\n| t_property_highlight_styles t_property_color {\n        $$ = rofi_theme_property_create ( P_HIGHLIGHT );\n        $$->value.highlight.style = $1|ROFI_HL_COLOR;\n        $$->value.highlight.color = $2;\n}\n| t_property_highlight_styles {\n        $$ = rofi_theme_property_create ( P_HIGHLIGHT );\n        $$->value.highlight.style = $1;\n}\n| t_property_color {\n        $$ = rofi_theme_property_create ( P_COLOR );\n        $$->value.color = $1;\n}\n| T_LIST_OPEN t_property_element_list_optional T_LIST_CLOSE {\n        $$ = rofi_theme_property_create ( P_LIST );\n        $$->value.list = $2;\n}\n| t_property_orientation {\n        $$ = rofi_theme_property_create ( P_ORIENTATION );\n        $$->value.i = $1;\n}\n| t_property_cursor {\n        $$ = rofi_theme_property_create ( P_CURSOR );\n        $$->value.i = $1;\n}\n| T_URL T_PARENT_LEFT T_STRING T_PARENT_RIGHT {\n        $$ = rofi_theme_property_create ( P_IMAGE );\n        $$->value.image.type = ROFI_IMAGE_URL;\n        $$->value.image.url  = $3;\n}\n| T_URL T_PARENT_LEFT T_STRING T_COMMA t_property_scale_type T_PARENT_RIGHT {\n        $$ = rofi_theme_property_create ( P_IMAGE );\n        $$->value.image.type    = ROFI_IMAGE_URL;\n        $$->value.image.url     = $3;\n        $$->value.image.scaling = $5;\n}\n| T_LINEAR_GRADIENT T_PARENT_LEFT t_color_list T_PARENT_RIGHT {\n        $$ = rofi_theme_property_create ( P_IMAGE );\n        $$->value.image.type   = ROFI_IMAGE_LINEAR_GRADIENT;\n        $$->value.image.dir    = ROFI_DIRECTION_RIGHT;\n        $$->value.image.colors = $3;\n}\n| T_LINEAR_GRADIENT T_PARENT_LEFT T_TO t_property_direction T_COMMA t_color_list T_PARENT_RIGHT {\n        $$ = rofi_theme_property_create ( P_IMAGE );\n        $$->value.image.type   = ROFI_IMAGE_LINEAR_GRADIENT;\n        $$->value.image.dir    = $4;\n        $$->value.image.colors = $6;\n}\n| T_LINEAR_GRADIENT T_PARENT_LEFT t_property_color_value_angle T_COMMA t_color_list T_PARENT_RIGHT {\n        $$ = rofi_theme_property_create ( P_IMAGE );\n        $$->value.image.type   = ROFI_IMAGE_LINEAR_GRADIENT;\n        $$->value.image.dir    = ROFI_DIRECTION_ANGLE;\n        $$->value.image.angle  = $3;\n        $$->value.image.colors = $5;\n}\n\n;\n\nt_property_direction\n: T_RIGHT   { $$ = ROFI_DIRECTION_RIGHT; }\n| T_LEFT    { $$ = ROFI_DIRECTION_LEFT; }\n| T_TOP     { $$ = ROFI_DIRECTION_TOP; }\n| T_BOTTOM  { $$ = ROFI_DIRECTION_BOTTOM; }\n;\nt_property_scale_type\n: T_BOTH    { $$ = ROFI_SCALE_BOTH; }\n| T_WIDTH   { $$ = ROFI_SCALE_WIDTH; }\n| T_HEIGHT  { $$ = ROFI_SCALE_HEIGHT; }\n| T_NONE    { $$ = ROFI_SCALE_NONE; }\n;\n\nt_color_list\n: t_property_color {\n    $$ = g_list_append ( NULL, g_memdup2 ( (gconstpointer)&($1), sizeof ( ThemeColor )));\n}\n| t_color_list T_COMMA t_property_color {\n\n    $$ = g_list_append ($1, g_memdup2 ( (gconstpointer)&($3), sizeof ( ThemeColor )));\n}\n;\n\n\n/** List of elements */\nt_property_element_list_optional\n: %empty { $$ = NULL; }\n| t_property_element_list { $$ = $1; }\n;\n\nt_property_element_list\n: t_property_element { $$ = g_list_append ( NULL, $1); }\n| T_ELEMENT {\n  Property *p = rofi_theme_property_create ( P_STRING );\n  p->value.s = $1;\n  $$ = g_list_append ( NULL, p);\n}\n| T_CALC {\n  Property *p = rofi_theme_property_create ( P_STRING );\n  p->value.s = g_strdup(\"calc\");\n  $$ = g_list_append ( NULL, p);\n}\n| t_property_element_list T_COMMA t_property_element {\n    $$ = g_list_append ( $1, $3 );\n}\n| t_property_element_list T_COMMA T_ELEMENT {\n  Property *p = rofi_theme_property_create ( P_STRING );\n  p->value.s = $3;\n  $$ = g_list_append ( $1, p);\n}\n| t_property_element_list T_COMMA T_CALC {\n  Property *p = rofi_theme_property_create ( P_STRING );\n  p->value.s = g_strdup(\"calc\");\n  $$ = g_list_append ( $1, p);\n}\n;\n\n/**\n * Position can be either center,\n * East or West, North Or South\n * Or combi of East or West and North or South\n */\nt_property_position\n: T_POS_CENTER { $$ =WL_CENTER;}\n| t_property_position_ew\n| t_property_position_sn\n| t_property_position_ew t_property_position_sn { $$ = $1|$2;}\n| t_property_position_sn t_property_position_ew { $$ = $1|$2;}\n;\nt_property_position_ew\n: T_POS_EAST   { $$ = WL_EAST;}\n| T_POS_WEST   { $$ = WL_WEST;}\n;\nt_property_position_sn\n: T_POS_NORTH  { $$ = WL_NORTH;}\n| T_POS_SOUTH  { $$ = WL_SOUTH;}\n;\n\n/**\n * Highlight style, allow mulitple styles to be combined.\n * Empty not allowed\n */\nt_property_highlight_styles\n: t_property_highlight_style { $$ = $1;}\n| t_property_highlight_styles t_property_highlight_style { $$ = $1|$2;}\n;\n/** Single style. */\nt_property_highlight_style\n: T_NONE          { $$ = ROFI_HL_NONE; }\n| T_BOLD          { $$ = ROFI_HL_BOLD; }\n| T_UNDERLINE     { $$ = ROFI_HL_UNDERLINE; }\n| T_STRIKETHROUGH { $$ = ROFI_HL_STRIKETHROUGH; }\n| T_ITALIC        { $$ = ROFI_HL_ITALIC; }\n| T_UPPERCASE     { $$ = ROFI_HL_UPPERCASE; }\n| T_LOWERCASE     { $$ = ROFI_HL_LOWERCASE; }\n| T_CAPITALIZE    { $$ = ROFI_HL_CAPITALIZE; }\n;\n\n\nt_property_distance_zero\n: t_property_number t_property_line_style {\n    $$.base.distance = $1;\n    $$.base.type     = ROFI_PU_PX;\n    $$.base.left     = NULL;\n    $$.base.right    = NULL;\n    $$.base.modtype  = ROFI_DISTANCE_MODIFIER_NONE;\n    $$.style         = $2;\n}\n| t_property_distance { $$ = $1;}\n;\n\n/** Distance. */\nt_property_distance_unit\n: t_property_number t_property_unit {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->distance = (double)$1;\n    $$->type     = $2;\n    $$->left     = NULL;\n    $$->right    = NULL;\n    $$->modtype  = ROFI_DISTANCE_MODIFIER_NONE;\n}\n| t_property_number {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->distance = (double)$1;\n    $$->type     = ROFI_PU_PX;\n    $$->left     = NULL;\n    $$->right    = NULL;\n    $$->modtype  = ROFI_DISTANCE_MODIFIER_NONE;\n}\n| T_PARENT_LEFT t_property_distance_unit_math3 T_PARENT_RIGHT {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->distance = 0;\n    $$->type     = ROFI_PU_PX;\n    $$->left     = $2;\n    $$->right    = 0;\n    $$->modtype  = ROFI_DISTANCE_MODIFIER_GROUP;\n};\n\n\n/**\n * Multiply/divide with auto-grouping.\n */\nt_property_distance_unit_math\n: t_property_distance_unit_math T_MODIFIER_MULTIPLY t_property_distance_unit {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_MULTIPLY;\n}\n| t_property_distance_unit_math T_FORWARD_SLASH t_property_distance_unit {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_DIVIDE;\n}\n| t_property_distance_unit_math T_MODIFIER_MODULO t_property_distance_unit {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_MODULO;\n}\n| t_property_distance_unit {\n    $$ = $1;\n};\n\n\n/** Level 2  (+-)*/\nt_property_distance_unit_math2\n: t_property_distance_unit_math2 T_MODIFIER_ADD t_property_distance_unit_math {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_ADD;\n}\n| t_property_distance_unit_math2 T_MIN t_property_distance_unit_math {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_SUBTRACT;\n}\n| t_property_distance_unit_math  {\n    $$ = $1;\n};\n/** Level 3  (min max)*/\nt_property_distance_unit_math3\n: t_property_distance_unit_math3 T_MODIFIER_MIN t_property_distance_unit_math2 {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_MIN;\n}\n| t_property_distance_unit_math3 T_MODIFIER_MAX t_property_distance_unit_math2 {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_MAX;\n}\n| t_property_distance_unit_math3 T_MODIFIER_ROUND t_property_distance_unit_math2 {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_ROUND;\n}\n| t_property_distance_unit_math3 T_MODIFIER_FLOOR t_property_distance_unit_math2 {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_FLOOR;\n}\n| t_property_distance_unit_math3 T_MODIFIER_CEIL t_property_distance_unit_math2 {\n    $$ = g_slice_new0(RofiDistanceUnit);\n    $$->left    = $1;\n    $$->right   = $3;\n    $$->modtype = ROFI_DISTANCE_MODIFIER_CEIL;\n}\n| t_property_distance_unit_math2  {\n    $$ = $1;\n};\n\n\nt_property_distance\n/** Integer unit and line style */\n: t_property_number t_property_unit t_property_line_style {\n    $$.base.distance = $1;\n    $$.base.type     = $2;\n    $$.base.left     = NULL;\n    $$.base.right    = NULL;\n    $$.base.modtype  = ROFI_DISTANCE_MODIFIER_NONE;\n    $$.style         = $3;\n}\n| T_CALC T_PARENT_LEFT t_property_distance_unit_math3 T_PARENT_RIGHT t_property_line_style {\n    $$.base.distance = 0;\n    $$.base.type     = ROFI_PU_PX;\n    $$.base.left     = $3;\n    $$.base.right    = NULL;\n    $$.base.modtype  = ROFI_DISTANCE_MODIFIER_GROUP;\n    $$.style         = $5;\n};\n\nt_property_number\n: T_INT { $$ = (double) $1; }\n| T_DOUBLE { $$ = $1; }\n| T_MIN t_property_number { $$ = -(double)$2; }\n\n/** distance unit. px, em, % */\nt_property_unit\n: T_UNIT_PX      { $$ = ROFI_PU_PX; }\n| T_UNIT_MM      { $$ = ROFI_PU_MM; }\n| T_UNIT_EM      { $$ = ROFI_PU_EM; }\n| T_UNIT_CH      { $$ = ROFI_PU_CH; }\n| T_PERCENT      { $$ = ROFI_PU_PERCENT; }\n;\n/******\n * Line style\n * If not set, solid.\n */\nt_property_line_style\n: %empty   { $$ = ROFI_HL_SOLID; }\n| T_SOLID  { $$ = ROFI_HL_SOLID; }\n| T_DASH   { $$ = ROFI_HL_DASH;  }\n;\n\n/**\n * Color formats\n */\nt_property_color\n /** rgba ( 0-255 , 0-255, 0-255, 0-1.0 ) */\n: T_COL_RGBA T_PARENT_LEFT  T_INT T_COMMA T_INT T_COMMA T_INT t_property_color_opt_alpha_c T_PARENT_RIGHT {\n    if ( ! check_in_range($3,0,255, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($5,0,255, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($7,0,255, &(@$)) ) { YYABORT; }\n    $$.alpha = $8;\n    $$.red   = $3/255.0;\n    $$.green = $5/255.0;\n    $$.blue  = $7/255.0;\n}\n /** rgba ( 0-255   0-255  0-255  / 0-1.0 ) */\n| T_COL_RGBA T_PARENT_LEFT  T_INT  T_INT  T_INT  t_property_color_opt_alpha_ws T_PARENT_RIGHT {\n    if ( ! check_in_range($3,0,255, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($4,0,255, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($5,0,255, &(@$)) ) { YYABORT; }\n    $$.alpha = $6;\n    $$.red   = $3/255.0;\n    $$.green = $4/255.0;\n    $$.blue  = $5/255.0;\n}\n /** rgba ( 0-100% , 0-100%, 0-100%, 0-1.0 ) */\n| T_COL_RGBA T_PARENT_LEFT  t_property_color_value T_PERCENT T_COMMA t_property_color_value T_PERCENT T_COMMA t_property_color_value T_PERCENT t_property_color_opt_alpha_c T_PARENT_RIGHT {\n    if ( ! check_in_range($3,0,100, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($6,0,100, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($9,0,100, &(@$)) ) { YYABORT; }\n    $$.alpha = $11;\n    $$.red   = $3/100.0;\n    $$.green = $6/100.0;\n    $$.blue  = $9/100.0;\n}\n /** rgba ( 0-100%   0-100%  0-100%  / 0-1.0 ) */\n| T_COL_RGBA T_PARENT_LEFT  t_property_color_value T_PERCENT  t_property_color_value T_PERCENT  t_property_color_value T_PERCENT  t_property_color_opt_alpha_ws T_PARENT_RIGHT {\n    if ( ! check_in_range($3,0,100, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($5,0,100, &(@$)) ) { YYABORT; }\n    if ( ! check_in_range($7,0,100, &(@$)) ) { YYABORT; }\n    $$.alpha = $9;\n    $$.red   = $3/100.0;\n    $$.green = $5/100.0;\n    $$.blue  = $7/100.0;\n}\n /** hwb with comma */\n| T_COL_HWB T_PARENT_LEFT t_property_color_value_angle T_COMMA t_property_color_value_unit T_COMMA t_property_color_value_unit t_property_color_opt_alpha_c T_PARENT_RIGHT {\n    double h = $3, w = $5, b = $7;\n    $$ = hwb_to_rgb ( h, w, b );\n    $$.alpha = $8;\n}\n /** hwb whitespace */\n| T_COL_HWB T_PARENT_LEFT t_property_color_value_angle  t_property_color_value_unit  t_property_color_value_unit t_property_color_opt_alpha_ws T_PARENT_RIGHT {\n    double h = $3, w = $4, b = $5;\n    $$ = hwb_to_rgb ( h, w, b );\n    $$.alpha = $6;\n}\n  /** cmyk  with comma */\n| T_COL_CMYK T_PARENT_LEFT t_property_color_value_unit T_COMMA t_property_color_value_unit T_COMMA t_property_color_value_unit T_COMMA t_property_color_value_unit t_property_color_opt_alpha_c T_PARENT_RIGHT {\n    $$.alpha = $10;\n    double c = $3, m = $5, y = $7, k = $9;\n    $$.red   = (1.0-c)*(1.0-k);\n    $$.green = (1.0-m)*(1.0-k);\n    $$.blue  = (1.0-y)*(1.0-k);\n}\n /** cmyk whitespace edition. */\n| T_COL_CMYK T_PARENT_LEFT t_property_color_value_unit  t_property_color_value_unit  t_property_color_value_unit t_property_color_value_unit t_property_color_opt_alpha_ws T_PARENT_RIGHT {\n    $$.alpha = $7;\n    double c = $3, m = $4, y = $5, k = $6;\n    $$.red   = (1.0-c)*(1.0-k);\n    $$.green = (1.0-m)*(1.0-k);\n    $$.blue  = (1.0-y)*(1.0-k);\n}\n /** hsl ( 0-360 0-100  % 0 - 100  % / alpha) */\n| T_COL_HSL T_PARENT_LEFT t_property_color_value_angle t_property_color_value_unit t_property_color_value_unit t_property_color_opt_alpha_ws T_PARENT_RIGHT {\n    double h = $3, s = $4, l = $5;\n    $$ = hsl_to_rgb ( h, s, l );\n    $$.alpha = $6;\n}\n /** hsl ( 0-360 , 0-100  %, 0 - 100  %) */\n| T_COL_HSL T_PARENT_LEFT t_property_color_value_angle T_COMMA t_property_color_value_unit T_COMMA t_property_color_value_unit t_property_color_opt_alpha_c T_PARENT_RIGHT {\n    double h = $3, s = $5, l = $7;\n    $$ = hsl_to_rgb ( h, s, l );\n    $$.alpha = $8;\n}\n/** Hex colors parsed by lexer. */\n| T_COLOR {\n    $$ = $1;\n}\n| T_COLOR_TRANSPARENT {\n    $$.alpha = 0.0;\n    $$.red = $$.green = $$.blue = 0.0;\n}\n| T_COLOR_NAME t_property_color_opt_alpha_ws {\n    $$ = $1;\n    $$.alpha  = $2;\n}\n;\nt_property_color_opt_alpha_c\n: %empty { $$ = 1.0; }\n| T_COMMA t_property_color_value_unit { $$ = $2;}\n;\nt_property_color_opt_alpha_ws\n: %empty { $$ = 1.0; }\n| T_FORWARD_SLASH t_property_color_value_unit { $$ = $2;}\n;\n t_property_color_value_angle\n: t_property_color_value              { $$ = $1/360.0;    if ( ! check_in_range ( $1, 0, 360, &(@$))){YYABORT;}}\n| t_property_color_value T_ANGLE_DEG  { $$ = $1/360.0;    if ( ! check_in_range ( $1, 0, 360, &(@$))){YYABORT;}}\n| t_property_color_value T_ANGLE_RAD  { $$ = $1/(2*G_PI); if ( ! check_in_range ( $1, 0.0, (2*G_PI), &(@$))){YYABORT;}}\n| t_property_color_value T_ANGLE_GRAD { $$ = $1/400.0;    if ( ! check_in_range ( $1, 0, 400, &(@$))){YYABORT;}}\n| t_property_color_value T_ANGLE_TURN { $$ = $1;          if ( ! check_in_range ( $1, 0.0, 1.0, &(@$))){YYABORT;}}\n;\n\nt_property_color_value_unit\n: t_property_color_value T_PERCENT { $$ = $1/100.0; if ( !check_in_range ( $1, 0, 100, &(@$))){YYABORT;}}\n| t_property_color_value           { $$ = $1;       if ( !check_in_range ( $1, 0.0, 1.0, &(@$))){YYABORT;}}\n;\n/** Color value to be double or integer. */\nt_property_color_value\n: T_DOUBLE { $$ = $1; }\n| T_INT    { $$ = $1; }\n;\n\nt_property_orientation\n: ORIENTATION_HORI { $$ = ROFI_ORIENTATION_HORIZONTAL; }\n| ORIENTATION_VERT { $$ = ROFI_ORIENTATION_VERTICAL;   }\n;\n\nt_property_cursor\n: CURSOR_DEF { $$ = ROFI_CURSOR_DEFAULT; }\n| CURSOR_PTR { $$ = ROFI_CURSOR_POINTER; }\n| CURSOR_TXT { $$ = ROFI_CURSOR_TEXT; }\n;\n\n/** Property name */\nt_property_name\n: T_PROP_NAME { $$ = $1; }\n;\n\nt_entry_name_path_selectors:\nt_entry_name_path { $$ = g_list_append  ( NULL, $1 ); }\n| t_entry_name_path_selectors T_SSEP t_entry_name_path {\n    $$ = g_list_append ( $1, $3);\n}\n| t_entry_name_path_selectors T_SSEP {\n   $$ = $1;\n}\n\n;\nt_entry_name_path:\nT_NAME_ELEMENT { $$ = g_list_append ( NULL, $1 );}\n| t_entry_name_path T_NSEP T_NAME_ELEMENT { $$ = g_list_append ( $1, $3);}\n| t_entry_name_path T_NSEP  { $$ = $1; }\n;\n\nt_property_name_list:\nt_property_name { $$ = g_list_append ( NULL, $1 );}\n| t_property_name_list T_SSEP t_property_name { $$ = g_list_append ( $1, $3);}\n;\n\n\n%%\n\n"
  },
  {
    "path": "meson-dist-script",
    "content": "#!/bin/sh\n\nset -eu\n\ncd \"${MESON_DIST_ROOT}\"\n\n# deploy docs\nmkdir build\nmeson setup build -Dprefix=/usr\nninja -C build\ncp build/doc/*.1 doc\ncp build/doc/*.5 doc\nrm -rf build\n\n# remove unwanted files in submodules\n# (.gitattributes only applies to the root repo)\nrm -f subprojects/*/.mailmap\nrm -f subprojects/*/.gitignore\nrm -f subprojects/*/.travis.yml\n"
  },
  {
    "path": "meson.build",
    "content": "project('rofi', 'c',\n    version: '2.0.0-dev',\n    meson_version: '>=0.59.0',\n    license: [ 'MIT' ],\n    default_options: [\n        'c_std=c99',\n        'warning_level=3'\n    ],\n)\n\nc_compiler = meson.get_compiler('c')\n\nadd_project_arguments(\n    '-I@0@'.format(meson.project_build_root()),\n    '-I@0@'.format(join_paths(meson.project_source_root(), 'include')),\n    '-D_DEFAULT_SOURCE=1',\n    language: 'c'\n)\n\nmeson.add_dist_script('meson-dist-script')\n\nflags = [\n    '-Wparentheses',\n    '-Winline',\n    '-Wunreachable-code',\n    '-Werror=missing-prototypes',\n    '-Wno-overlength-strings',\n    '-Wno-inline', # A bit too noisy with Bison…\n    '-Wshadow'\n]\nforeach f : flags\n    if c_compiler.has_argument(f)\n        add_project_arguments(f, language: 'c')\n    endif\nendforeach\n\nif get_option('b_lto')\n  add_project_arguments('-Werror=odr', language: 'c')\n  add_project_arguments('-Werror=lto-type-mismatch', language: 'c')\n  add_project_arguments('-Werror=strict-aliasing', language: 'c')\nendif\n\nplugindir  = join_paths(get_option('libdir'), meson.project_name())\nthemedir   = join_paths(get_option('datadir'), meson.project_name(), 'themes')\ndesktop_install_dir = join_paths(get_option('datadir'), 'applications')\nicondir    = join_paths(get_option('datadir'), 'icons','hicolor', 'scalable', 'apps')\n\nglib_min_major=2\nglib_min_minor=72\nglib_min_version='@0@.@1@'.format(glib_min_major, glib_min_minor)\nplugins_deps = [\n    dependency('glib-2.0', version: '>= @0@'.format(glib_min_version)),\n    dependency('gmodule-2.0'),\n    dependency('cairo'),\n]\n\ndep_lm = c_compiler.find_library('m', required : false)\n\ndeps = [\n    plugins_deps,\n    dependency('gio-unix-2.0'),\n    dependency('pango'),\n    dependency('pangocairo'),\n    dependency('xkbcommon'),\n    dependency('gdk-pixbuf-2.0'),\n    dep_lm,\n]\n\nlibgwater = subproject('libgwater')\n\n##\n# Check if atleast xcb or wayland is allowed in build configuration.\n# No point in having no backend.\n##\nxcb_opt = get_option('xcb')\nwayland_opt = get_option('wayland')\nassert(xcb_opt.allowed() or wayland_opt.allowed(),\n    'At least one of these options must be allowed: wayland, xcb')\n\n# XCB stuff\nxcb = dependency('xcb', required: xcb_opt)\nxcb_deps = [\n    xcb,\n    dependency('xcb-aux', required: xcb_opt),\n    dependency('xcb-xkb', required: xcb_opt),\n    dependency('xkbcommon-x11', required: xcb_opt),\n    dependency('xcb-ewmh', required: xcb_opt),\n    dependency('xcb-icccm', required: xcb_opt),\n    dependency('xcb-randr', required: xcb_opt),\n    dependency('xcb-cursor', required: xcb_opt),\n    dependency('xcb-xinerama', required: xcb_opt),\n    dependency('xcb-keysyms', required: xcb_opt),\n    dependency('cairo-xcb', required: xcb_opt),\n    dependency('libstartup-notification-1.0', required: xcb_opt),\n]\n\nxcb_enabled = xcb_opt.allowed()\nforeach dep: xcb_deps\n  xcb_enabled = xcb_enabled and dep.found()\nendforeach\n\nif xcb_enabled\n  deps += xcb_deps + [libgwater.get_variable('libgwater_xcb')]\nendif\n\nwayland_protocols = dependency('wayland-protocols', version: '>= 1.17', required: wayland_opt)\nwayland_deps = [\n  dependency('wayland-client', required: wayland_opt),\n  wayland_protocols,\n  dependency('wayland-cursor', required: wayland_opt),\n]\n\nwayland_enabled = wayland_opt.allowed()\nforeach dep: wayland_deps\n  wayland_enabled = wayland_enabled and dep.found()\nendforeach\n\nif wayland_enabled\n  deps += wayland_deps + [libgwater.get_variable('libgwater_wayland')]\nendif\n\n##\n# If both in auto mode, but none found. Check again if atleast one exists.\n##\n\nassert(xcb_enabled or wayland_enabled,\n    'At least one of these options must be found: wayland, xcb')\n\nheader_conf = configuration_data()\nif get_option('imdkit')\n  imdkit_new  = dependency('xcb-imdkit', version: '>= 1.0.3', required: false)\n  imdkit_old  = dependency('xcb-imdkit', version: '<= 1.0.2', required: false)\n  if imdkit_new.found()\n    deps += imdkit_new\n    header_conf.set('XCB_IMDKIT_1_0_3_LOWER', false)\n    header_conf.set('XCB_IMDKIT', true)\n  elif imdkit_old.found()\n    deps+= imdkit_old\n    header_conf.set('XCB_IMDKIT_1_0_3_LOWER', true)\n    header_conf.set('XCB_IMDKIT', true)\n  else\n    header_conf.set('XCB_IMDKIT_1_0_3_LOWER', false)\n    header_conf.set('XCB_IMDKIT', false)\n  endif\nendif\n\n\ncheck = dependency('check', version: '>= 0.11.0', required: get_option('check'))\n\n\n\nheader_conf.set_quoted('PACKAGE_NAME', meson.project_name())\nheader_conf.set_quoted('PACKAGE_VERSION', meson.project_version())\nheader_conf.set_quoted('VERSION', meson.project_version())\nheader_conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())\nheader_conf.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/davatorium/rofi/')\nheader_conf.set_quoted('PACKAGE_URL', 'https://github.com/davatorium/rofi/discussions')\n\nheader_conf.set('_GNU_SOURCE', true)\n\nheader_conf.set('USE_NK_GIT_VERSION', true)\n\nheader_conf.set('GLIB_VERSION_MIN_REQUIRED', '(G_ENCODE_VERSION(@0@,@1@))'.format(glib_min_major, glib_min_minor))\nheader_conf.set('GLIB_VERSION_MAX_ALLOWED', '(G_ENCODE_VERSION(@0@,@1@))'.format(glib_min_major, glib_min_minor))\n\nheader_conf.set('ENABLE_DRUN', get_option('drun'))\nheader_conf.set('WINDOW_MODE', get_option('window'))\n\nheader_conf.set('ENABLE_WAYLAND', wayland_enabled)\nheader_conf.set('ENABLE_XCB', xcb_enabled)\n\nheader_conf.set_quoted('MANPAGE_PATH', join_paths(get_option('prefix'), get_option('mandir')))\nheader_conf.set_quoted('SYSCONFDIR', join_paths(get_option('prefix'), get_option('sysconfdir')))\nheader_conf.set_quoted('PLUGIN_PATH', join_paths(get_option('prefix'), plugindir))\nheader_conf.set_quoted('THEME_DIR', join_paths(get_option('prefix'), themedir))\n\nconfig_h = configure_file(output: 'config.h', configuration: header_conf)\n\nnk_options = [\n    'bindings=true',\n    'git-work-tree=@0@'.format(meson.project_source_root()),\n]\nnk = subproject('libnkutils', default_options: nk_options)\nnk_subproject_options = nk.get_variable('nk_options')\nforeach o : nk_options + nk_subproject_options\n    if ( o.startswith('git-work-tree=') )\n        continue\n    elif not nk_options.contains(o) or not nk_subproject_options.contains(o)\n        error('You must not change libnkutils options @0@ != @1@'.format('|'.join(nk_options), '|'.join(nk_subproject_options)))\n    endif\nendforeach\ndeps += nk.get_variable('libnkutils')\ndeps += nk.get_variable('libnkutils_bindings')\n\ninstall_headers([\n        'include/mode.h',\n        'include/mode-private.h',\n        'include/helper.h',\n        'include/rofi-types.h',\n        'include/rofi-icon-fetcher.h'\n    ],\n    subdir: meson.project_name(),\n)\ninstall_data(\n    'script/rofi-sensible-terminal',\n    'script/rofi-theme-selector',\n    install_dir: join_paths(get_option('prefix'), get_option('bindir'))\n)\n\ninstall_data(\n  'data/rofi-theme-selector.desktop',\n  'data/rofi.desktop',\n  install_dir: desktop_install_dir\n  )\ninstall_data(\n  'data/rofi.svg',\n  install_dir: icondir\n)\n\nflex = generator(find_program('flex'),\n    output: '@BASENAME@.c',\n    arguments: [ '-o', '@OUTPUT@', '@INPUT@' ]\n)\nbison = generator(find_program('bison'),\n    output: [ '@BASENAME@.c', '@BASENAME@.h' ],\n    arguments: [ '--report=all', '--report-file=bison.log', '-Wall', '--verbose', '-d', '@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@' ]\n)\n\nrofi_sources = files(\n        'source/rofi.c',\n        'source/mode.c',\n        'source/keyb.c',\n        'config/config.c',\n        'source/display.c',\n        'source/helper.c',\n        'source/timings.c',\n        'source/history.c',\n        'source/theme.c',\n        'source/rofi-icon-fetcher.c',\n        'source/css-colors.c',\n        'source/view.c',\n        'source/widgets/box.c',\n        'source/widgets/icon.c',\n        'source/widgets/container.c',\n        'source/widgets/widget.c',\n        'source/widgets/textbox.c',\n        'source/widgets/listview.c',\n        'source/widgets/scrollbar.c',\n        'source/xrmoptions.c',\n        'source/rofi-types.c',\n        'source/modes/run.c',\n        'source/modes/ssh.c',\n        'source/modes/drun.c',\n        'source/modes/dmenu.c',\n        'source/modes/combi.c',\n        'source/modes/script.c',\n        'source/modes/help-keys.c',\n        'source/modes/filebrowser.c',\n        'source/modes/recursivebrowser.c',\n        'include/display.h',\n        'include/xcb.h',\n        'include/rofi.h',\n        'include/mode.h',\n        'include/mode-private.h',\n        'include/settings.h',\n        'include/keyb.h',\n        'include/view.h',\n        'include/view-internal.h',\n        'include/rofi-icon-fetcher.h',\n        'include/helper.h',\n        'include/helper-theme.h',\n        'include/timings.h',\n        'include/history.h',\n        'include/theme.h',\n        'include/rofi-types.h',\n        'include/css-colors.h',\n        'include/widgets/box.h',\n        'include/widgets/icon.h',\n        'include/widgets/container.h',\n        'include/widgets/widget.h',\n        'include/widgets/widget-internal.h',\n        'include/widgets/textbox.h',\n        'include/widgets/listview.h',\n        'include/widgets/scrollbar.h',\n        'include/xrmoptions.h',\n        'include/modes/ssh.h',\n        'include/modes/run.h',\n        'include/modes/drun.h',\n        'include/modes/dmenu.h',\n        'include/modes/combi.h',\n        'include/modes/script.h',\n        'include/modes/modes.h',\n        'include/modes/help-keys.h',\n        'include/modes/filebrowser.h',\n        'include/modes/dmenuscriptshared.h',\n)\nif xcb_enabled\n    rofi_sources += files(\n        'source/modes/window.c',\n        'source/xcb/display.c',\n        'source/xcb/view.c',\n        'include/modes/window.h',\n        'include/xcb-internal.h',\n    )\nendif\n\ntheme_lexer_sources = files('lexer/theme-lexer.l')\ntheme_parser_sources = files('lexer/theme-parser.y')\n\ntheme_lexer = flex.process(theme_lexer_sources)\ntheme_parser = bison.process(theme_parser_sources)\n\nif wayland_enabled\n    fs = import('fs')\n    wayland_sys_protocols_dir = wayland_protocols.get_variable(pkgconfig: 'pkgdatadir')\n    wayland_scanner = find_program('wayland-scanner')\n    protocols = files(\n        wayland_sys_protocols_dir + '/stable/xdg-shell/xdg-shell.xml',\n        wayland_sys_protocols_dir + '/unstable/primary-selection/primary-selection-unstable-v1.xml',\n        wayland_sys_protocols_dir + '/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml',\n        wayland_sys_protocols_dir + '/unstable/text-input/text-input-unstable-v3.xml',\n        'protocols/wlr-foreign-toplevel-management-unstable-v1.xml',\n        'protocols/wlr-layer-shell-unstable-v1.xml',\n    )\n\n    if wayland_protocols.version().version_compare('>=1.32')\n        add_project_arguments('-DHAVE_WAYLAND_CURSOR_SHAPE', language: 'c')\n        protocols += files(\n            wayland_sys_protocols_dir + '/staging/cursor-shape/cursor-shape-v1.xml',\n            wayland_sys_protocols_dir + '/unstable/tablet/tablet-unstable-v2.xml',\n        )\n    endif\n\n    proto_srcs = []\n    proto_headers = []\n    foreach p : protocols\n        proto_srcs += custom_target(\n            fs.stem(p).underscorify() + '_protocol_c',\n            input: p,\n            output: '@BASENAME@-protocol.c',\n            command: [wayland_scanner, 'public-code', '@INPUT@', '@OUTPUT@'],\n        )\n        proto_headers += custom_target(\n            fs.stem(p).underscorify() + '_protocol_h',\n            input: p,\n            output: '@BASENAME@-protocol.h',\n            command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],\n        )\n    endforeach\n\n    rofi_sources += proto_srcs\n    rofi_sources += proto_headers\n    rofi_sources += files(\n        'source/modes/wayland-window.c',\n        'source/wayland/view.c',\n        'source/wayland/display.c',\n        'include/modes/wayland-window.h',\n        'include/wayland-internal.h',\n    )\nendif\n\n\ngnome = import('gnome')\ndefault_theme = gnome.compile_resources('resources', files('resources/resources.xml'))\n\nrofi = executable('rofi', rofi_sources + [\n        theme_lexer,\n        theme_parser,\n        default_theme,\n    ],\n    dependencies: deps,\n    install: true,\n)\n\nsubdir('doc')\n\ninstall_data(\n    'themes/Adapta-Nokto.rasi',\n    'themes/Arc.rasi',\n    'themes/Arc-Dark.rasi',\n    'themes/DarkBlue.rasi',\n    'themes/Indego.rasi',\n    'themes/Monokai.rasi',\n    'themes/Paper.rasi',\n    'themes/android_notification.rasi',\n    'themes/arthur.rasi',\n    'themes/blue.rasi',\n    'themes/c64.rasi',\n    'themes/dmenu.rasi',\n    'themes/docu.rasi',\n    'themes/glue_pro_blue.rasi',\n    'themes/gruvbox-common.rasinc',\n    'themes/gruvbox-dark-hard.rasi',\n    'themes/gruvbox-dark-soft.rasi',\n    'themes/gruvbox-dark.rasi',\n    'themes/gruvbox-light-hard.rasi',\n    'themes/gruvbox-light-soft.rasi',\n    'themes/gruvbox-light.rasi',\n    'themes/lb.rasi',\n    'themes/paper-float.rasi',\n    'themes/purple.rasi',\n    'themes/sidebar.rasi',\n    'themes/sidebar-v2.rasi',\n    'themes/solarized.rasi',\n    'themes/solarized_alternate.rasi',\n    'themes/fancy.rasi',\n    'themes/fancy2.rasi',\n    'themes/iggy.rasi',\n    'themes/material.rasi',\n    'themes/iggy.jpg',\n    'themes/fullscreen-preview.rasi',\n    install_dir: themedir\n)\n\npkg = import('pkgconfig')\n\npkg.generate(\n    filebase: 'rofi',\n    name: 'rofi',\n    version: meson.project_version().split('+')[0],\n    description: 'Header files for rofi plugins',\n    variables: [\n        'pluginsdir=@0@'.format(join_paths('${libdir}', meson.project_name())),\n    ],\n    requires_private: plugins_deps,\n)\n\n\ntest('history test', executable('history.test', [\n        'test/history-test.c',\n    ],\n    objects: rofi.extract_objects([\n        'source/history.c',\n        'config/config.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('helper_pidfile test', executable('helper_pidfile.test', [\n        'test/helper-pidfile.c',\n    ],\n    objects: rofi.extract_objects([\n        'config/config.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'source/xrmoptions.c',\n        'source/rofi-types.c',\n    ]),\n    dependencies: deps,\n))\n\n\ntest('widget test', executable('widget.test', [\n        'test/widget-test.c',\n        theme_parser,\n        theme_lexer,\n        default_theme,\n    ],\n    objects: rofi.extract_objects([\n        'source/widgets/widget.c',\n        'source/widgets/textbox.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/rofi-types.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'config/config.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('box test', executable('box.test', [\n        'test/box-test.c',\n        theme_parser,\n        theme_lexer,\n        default_theme,\n    ],\n    objects: rofi.extract_objects([\n        'source/widgets/widget.c',\n        'source/widgets/box.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/rofi-types.c',\n        'source/css-colors.c',\n        'config/config.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('scrollbar test', executable('scrollbar.test', [\n        'test/scrollbar-test.c',\n        theme_parser,\n        theme_lexer,\n        default_theme,\n    ],\n    objects: rofi.extract_objects([\n        'source/widgets/widget.c',\n        'source/widgets/scrollbar.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/rofi-types.c',\n        'source/css-colors.c',\n        'config/config.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('textbox test', executable('textbox.test', [\n        'test/textbox-test.c',\n        theme_parser,\n        theme_lexer,\n        default_theme,\n    ],\n    objects: rofi.extract_objects([\n        'source/widgets/widget.c',\n        'source/widgets/textbox.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/rofi-types.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'config/config.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('helper test', executable('helper.test', [\n        'test/helper-test.c',\n    ],\n    objects: rofi.extract_objects([\n        'config/config.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'source/xrmoptions.c',\n        'source/rofi-types.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('helper_expand test', executable('helper_expand.test', [\n        'test/helper-expand.c',\n    ],\n    objects: rofi.extract_objects([\n        'config/config.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'source/xrmoptions.c',\n        'source/rofi-types.c',\n    ]),\n    dependencies: deps,\n))\n\ntest('helper_config_cmdline_parser test', executable('helper_config_cmdline_parser.test', [\n        'test/helper-config-cmdline-parser.c',\n    ],\n    objects: rofi.extract_objects([\n        'config/config.c',\n        'source/theme.c',\n        'source/css-colors.c',\n        'source/helper.c',\n        'source/xrmoptions.c',\n        'source/rofi-types.c',\n    ]),\n    dependencies: deps,\n))\n\nif check.found()\n    deps+= [ check ]\n\n    test('theme_parser test', executable('theme_parser.test', [\n            'test/theme-parser-test.c',\n            theme_lexer,\n            theme_parser,\n            default_theme,\n        ],\n        objects: rofi.extract_objects([\n            'config/config.c',\n            'source/helper.c',\n            'source/xrmoptions.c',\n            'source/theme.c',\n            'source/css-colors.c',\n            'source/rofi-types.c',\n            'source/css-colors.c',\n        ]),\n        dependencies: deps,\n    ))\n\n    test('mode test', executable('mode.test', [\n            'test/mode-test.c',\n        ],\n        objects: rofi.extract_objects([\n            'config/config.c',\n            'source/modes/help-keys.c',\n            'source/helper.c',\n            'source/theme.c',\n            'source/css-colors.c',\n            'source/mode.c',\n            'source/xrmoptions.c',\n            'source/rofi-types.c',\n            'source/keyb.c',\n        ]),\n        dependencies: deps,\n    ))\n\n    test('helper_tokenize test', executable('helper_tokenize.test', [\n            'test/helper-tokenize.c',\n        ],\n        objects: rofi.extract_objects([\n            'config/config.c',\n            'source/helper.c',\n            'source/theme.c',\n            'source/css-colors.c',\n            'source/xrmoptions.c',\n            'source/rofi-types.c',\n        ]),\n        dependencies: deps,\n    ))\nendif\n\n\nrofi_sources += theme_lexer_sources\nrofi_sources += theme_parser_sources\n\ncppcheck = find_program('cppcheck', required: false)\nif cppcheck.found()\n    run_target('cppcheck',\n        command: [\n            cppcheck,\n            '--std=@0@'.format(get_option('c_std')),\n            '--platform=unix64',\n            '--enable=all',\n            '-Uerror_dialog',\n            '--inconclusive',\n            '-I@0@'.format(join_paths(meson.project_source_root(), 'include')),\n            rofi_sources\n        ],\n    )\nendif\n\nohcount = find_program('ohcount', required: false)\nif ohcount.found()\n    run_target('ohcount',\n        command: [\n            ohcount,\n            rofi_sources\n        ],\n    )\nendif\n"
  },
  {
    "path": "meson_options.txt",
    "content": "option('drun', type: 'boolean', value: true, description: 'Desktop file mode')\noption('window', type: 'boolean', value: true, description: 'Window switcher mode')\noption('check', type: 'feature', description: 'Build and run libcheck-based tests')\noption('imdkit', type: 'boolean', value: true, description: 'IMDKit support')\noption('wayland', type: 'feature', value: 'auto', description: 'Build with wayland support')\noption('xcb', type: 'feature', value: 'auto', description: 'Build with X11/xcb support')\n"
  },
  {
    "path": "mkdocs/docs/1.7.0/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable modi.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a list and process the result from user\nactions.  This provide a simple interface to make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modi \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a list of options, separated by a newline\n(`\\n`) (This can be changed by the script).\nIf the user selects an option, rofi calls the executable with the text of that option as the first argument.\nIf the script returns no entries, rofi quits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nQuentin Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.0/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is utf-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with a hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path should always start with a `#`.\nMultiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly inherited from their parent with the\n`inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox` is a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the highlighted text.\n * `strikethrough`: put a line through the highlighted text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\nIt supports the following operations:\n\n* `+`   : Add\n* `-`   : Subtract\n* `/`   : Divide\n* `*`   : Multiply\n* `%`   : Multiply\n* `min` : Minimum of l or rvalue;\n* `max` : Maximum of l or rvalue;\n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n## Position\n\nIndicate a place on the window/monitor.\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n```\n\nnorth west   |    north    |  north east\n-------------|-------------|------------\n      west   |   center    |  east\n-------------|-------------|------------\nsouth west   |    south    |  south east\n```\n\n## Visibility\n\nIt is possible to hide widgets:\n\ninputbar {\n    enabled: false;\n}\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:         enable/disable the widget\n* **padding**:         padding\n  Padding on the inside of the widget\n* **margin**:          padding\n  Margin on the outside of the widget\n* **border**:          border\n  Border around the widget (between padding and margin)/\n* **border-radius**:    padding\n  Sets a radius on the corners of the borders.\n* **background-color**:      color\n  Background color\n* **background-image**:      image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:      cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:  distance\n* **y-offset**:  distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:         distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**:               the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n|------------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                              |\n| |-------------------------------------------------------------------------------|  |\n| | mainbox  {BOX:vertical}                                                       |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | inputbar {BOX:horizontal}                                                 | |  |\n| | | |---------| |-| |---------------------------------|---| |---| |---| |---| | |  |\n| | | | prompt  | |:| | entry                           |#fr| | / | |#ns| |ci | | |  |\n| | | |---------| |_| |---------------------------------|---| |---| |---| |---| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | message                                                                   | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | | | textbox                                                               | | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |-----------------------------------------------------------------------------|  |\n| | | listview                                                                    |  |\n| | |-----------------------------------------------------------------------------|  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | |  mode-switcher {BOX:horizontal}                                           | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | | | Button        |   | Button        |  | Button       | | Button        | | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |-------------------------------------------------------------------------------|  |\n|------------------------------------------------------------------------------------|\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n|-----------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                             |\n| |------------------------------------------------------------------------------|  |\n| | error-message {BOX:vertical}                                                 |  |\n| | |-------------------------------------------------------------------------|  |  |\n| | | textbox                                                                 |  |  |\n| | | |-----------------| |-------------------------------------------------| |  |  |\n| | | |element-icon     | |element-text                                     | |  |  |\n| | | |-----------------| |-------------------------------------------------| |  |  |\n| | |-------------------------------------------------------------------------|  |  |\n| |------------------------------------------------------------------------------|  |\n|-----------------------------------------------------------------------------------|\n\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n|-------------------------------------------------------------------|\n| margin                                                            |\n|  |-------------------------------------------------------------|  |\n|  | border                                                      |  |\n|  | |---------------------------------------------------------| |  |\n|  | | padding                                                 | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | | | content                                             | | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | |---------------------------------------------------------| |  |\n|  |-------------------------------------------------------------|  |\n|-------------------------------------------------------------------|\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n|---------------------------------------|\n|  |--------| s |--------| s |-------|  |\n|  | child  | p | child  | p | child |  |\n|  |        | a |        | a |       |  |\n|  |        | c |        | c |       |  |\n|  |        | i |        | i |       |  |\n|  |        | n |        | n |       |  |\n|  |--------| g |--------| g |-------|  |\n|---------------------------------------|\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n|--------------------------------------------|\n|  |-----------|  |--------|  |-----------|  |\n|  | dummy     |  | child  |  | dummy     |  |\n|  | expand: y |  |        |  | expand: y |  |\n|  |           |  |        |  |           |  |\n|  |           |  |        |  |           |  |\n|  |           |  |        |  |           |  |\n|  |-----------|  |--------|  |-----------|  |\n|--------------------------------------------|\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.0/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and more. It focuses on\nbeing fast to use and have minimal distraction. It supports keyboard and mouse navigation, type to\nfilter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to quickly switch\nbetween windows, start applications or log into a remote machine via `ssh`.\nThere are different *modi* for different types of actions.\n\n**rofi** can also function as (drop-in) replacement for **dmenu(1)**.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `run` dialog:\n\n    rofi -show run\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with the `-dmenu` flag.\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set values.\nThese include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`, `ssh`, `combi`.\nThe special argument `keys` can be used to open a searchable list of supported key bindings\n(see *KEY BINDINGS*)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modi is shown.\n\n`-modi` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modi \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has two parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modi \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modi \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-fallback-application-icon`\n\nSpecify an icon to be used when the application icon in run/drun are not yet loaded or is not available.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines (See the `-lines` option.)\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modi` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode -lines 0\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\n### Combi settings\n\n`-combi-modi` *mode1*,*mode2*\n\nThe modi to combine in combi mode.\nFor syntax to `-combi-modi`, see `-modi`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modi \"window,run,ssh\" -modi combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n### Dmenu specific\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -lines 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-async-pre-read` *number*\n\nReads the first *number* entries blocking, then switches to async mode.\nThis makes it feel more 'snappy'.\n\n*default*: 25\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal-emulator)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n## DMENU REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\n**rofi** has the following key bindings:\n\n  * `Control-v, Insert`: Paste from clipboard\n  * `Control-Shift-v, Shift-Insert`: Paste primary selection\n  * `Control-u`: Clear the line\n  * `Control-a`: Beginning of line\n  * `Control-e`: End of line\n  * `Control-f, Right`: Forward one character\n  * `Alt-f, Control-Right`: Forward one word\n  * `Control-b, Left`: Back one character\n  * `Alt-b, Control-Left`: Back one word\n  * `Control-d, Delete`: Delete character\n  * `Control-Alt-d`: Delete word\n  * `Control-h, Backspace, Shift-Backspace`: Backspace (delete previous character)\n  * `Control-Alt-h`: Delete previous word\n  * `Control-j,Control-m,Enter`: Accept entry\n  * `Control-n,Down`: Select next entry\n  * `Control-p,Up`: Select previous entry\n  * `Page Up`: Go to previous page\n  * `Page Down`: Go to next page\n  * `Control-Page Up`: Go to previous column\n  * `Control-Page Down`: Go to next column\n  * `Control-Enter`: Use entered text as a command (in `ssh/run modi`)\n  * `Shift-Enter`: Launch the application in a terminal (in run mode)\n  * `Control-Shift-Enter`: As Control-Enter and run the command in terminal (in run mode)\n  * `Shift-Enter`: Return the selected entry and move to the next item while keeping **rofi** open. (in dmenu)\n  * `Shift-Right`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Shift-Left`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-Tab`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Control-Shift-Tab`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-space`: Set selected item as input text.\n  * `Shift-Del`: Delete entry from history.\n  * `grave`: Toggle case sensitivity.\n  * `Alt-grave`: Toggle sorting.\n  * `Alt-Shift-S`: Take a screenshot and store it in the Pictures directory.\n  * `Control-l`: File complete for run dialog.\n\nThis list might not be complete, to get a full list of all key bindings\nsupported in your rofi, see `rofi -h`. The options starting with `-kb` are keybindings.\n\nKey bindings can be modified using the configuration systems. Multiple keys can be bound\nto one action by comma separating them. For example `-kb-primary-paste \"Conctrol+v,Insert\"`\n\nTo get a searchable list of key bindings, run `rofi -show keys`.\n\nA key binding starting with `!` will act when all keys have been released.\n\n## Available Modi\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modi to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modi in one list. Specify which modi are included with the `-combi-modi` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modi.\nAll modi that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modi run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodi are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modi.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font.\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modi run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modi run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modi combi -show combi -combi-modi run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modi combi,window -show combi -combi-modi run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\nUse `qalc` to get a simple calculator in **rofi**:\n\n     rofi -show calc -modi \"calc:qalc +u8 -nocurrencies\"\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://davedavenport.github.io/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nTo debug, it is smart to first try disabling your custom configuration:\n`-no-config`\n\nDisable parsing of configuration. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable them using:\n\n`-no-plugins`\n\nDisables the loading of plugins.\n\nTo further debug the plugin, you can get a trace with (lots of) debug information.  This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G_MESSAGES_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Dialogs.DMenu: The dmenu mode.\n * Dialogs.Run: The run mode.\n * Dialogs.DRun: The desktop file run mode.\n * Dialogs.Window: The window mode.\n * Dialogs.Script: The script mode.\n * Dialogs.Combi: The script mode.\n * Dialogs.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nThe output of this can provide useful information when writing an issue.\n\nMore information (possibly outdated) see [this](https://github.com/DaveDavenport/rofi/wiki/Debugging%20Rofi) wiki entry.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/DaveDavenport/rofi/issues)\n\nWhen creating an issue, please read [this](https://github.com/DaveDavenport/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Quentin Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.1/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable modi.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a list and process the result from user\nactions.  This provide a simple interface to make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modi \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a list of options, separated by a newline\n(`\\n`) (This can be changed by the script).\nIf the user selects an option, rofi calls the executable with the text of that option as the first argument.\nIf the script returns no entries, rofi quits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nQuentin Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.1/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## DEFAULT THEME LOADING\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nIn the default (always loaded) configuration it does:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add `@theme` to your\n`config.rasi` file.\n\nIf you have a theme loaded by `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is utf-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with a hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path should always start with a `#`.\nMultiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly inherited from their parent with the\n`inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox` is a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the highlighted text.\n * `strikethrough`: put a line through the highlighted text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\nIt supports the following operations:\n\n* `+`   : Add\n* `-`   : Subtract\n* `/`   : Divide\n* `*`   : Multiply\n* `%`   : Multiply\n* `min` : Minimum of l or rvalue;\n* `max` : Maximum of l or rvalue;\n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n## Position\n\nIndicate a place on the window/monitor.\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n```\n\nnorth west   |    north    |  north east\n-------------|-------------|------------\n      west   |   center    |  east\n-------------|-------------|------------\nsouth west   |    south    |  south east\n```\n\n## Visibility\n\nIt is possible to hide widgets:\n\ninputbar {\n    enabled: false;\n}\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n* Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the property\n`width` is not set, the default value is used.\n\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n* Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\nIf the environment value is not found, the default value is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default value (`40%`).\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:         enable/disable the widget\n* **padding**:         padding\n  Padding on the inside of the widget\n* **margin**:          padding\n  Margin on the outside of the widget\n* **border**:          border\n  Border around the widget (between padding and margin)/\n* **border-radius**:    padding\n  Sets a radius on the corners of the borders.\n* **background-color**:      color\n  Background color\n* **background-image**:      image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:      cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:  distance\n* **y-offset**:  distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:         distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**:               the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n|------------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                              |\n| |-------------------------------------------------------------------------------|  |\n| | mainbox  {BOX:vertical}                                                       |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | inputbar {BOX:horizontal}                                                 | |  |\n| | | |---------| |-| |---------------------------------|---| |---| |---| |---| | |  |\n| | | | prompt  | |:| | entry                           |#fr| | / | |#ns| |ci | | |  |\n| | | |---------| |_| |---------------------------------|---| |---| |---| |---| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | message                                                                   | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | | | textbox                                                               | | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |-----------------------------------------------------------------------------|  |\n| | | listview                                                                    |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | | | element                                                                |  |  |\n| | | | |-----------------| |------------------------------------------------] |  |  |\n| | | | |element-icon     | |element-text                                    | |  |  |\n| | | | |-----------------| |------------------------------------------------| |  |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | |-----------------------------------------------------------------------------|  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | |  mode-switcher {BOX:horizontal}                                           | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | | | Button        |   | Button        |  | Button       | | Button        | | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |-------------------------------------------------------------------------------|  |\n|------------------------------------------------------------------------------------|\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n|-----------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                             |\n| |------------------------------------------------------------------------------|  |\n| | error-message {BOX:vertical}                                                 |  |\n| | |-------------------------------------------------------------------------|  |  |\n| | | textbox                                                                 |  |  |\n| | |-------------------------------------------------------------------------|  |  |\n| |------------------------------------------------------------------------------|  |\n|-----------------------------------------------------------------------------------|\n\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n|-------------------------------------------------------------------|\n| margin                                                            |\n|  |-------------------------------------------------------------|  |\n|  | border                                                      |  |\n|  | |---------------------------------------------------------| |  |\n|  | | padding                                                 | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | | | content                                             | | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | |---------------------------------------------------------| |  |\n|  |-------------------------------------------------------------|  |\n|-------------------------------------------------------------------|\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n|---------------------------------------|\n|  |--------| s |--------| s |-------|  |\n|  | child  | p | child  | p | child |  |\n|  |        | a |        | a |       |  |\n|  |        | c |        | c |       |  |\n|  |        | i |        | i |       |  |\n|  |        | n |        | n |       |  |\n|  |--------| g |--------| g |-------|  |\n|---------------------------------------|\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n|----------------------------------------------------|\n|  |---------------|  |--------|  |---------------|  |\n|  | dummy         |  | child  |  | dummy         |  |\n|  | expand: true; |  |        |  | expand: true; |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |---------------|  |--------|  |---------------|  |\n|----------------------------------------------------|\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.1/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and more. It focuses on\nbeing fast to use and have minimal distraction. It supports keyboard and mouse navigation, type to\nfilter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to quickly switch\nbetween windows, start applications or log into a remote machine via `ssh`.\nThere are different *modi* for different types of actions.\n\n**rofi** can also function as (drop-in) replacement for **dmenu(1)**.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `run` dialog:\n\n    rofi -show run\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with the `-dmenu` flag.\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set values.\nThese include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`, `ssh`, `combi`.\nThe special argument `keys` can be used to open a searchable list of supported key bindings\n(see *KEY BINDINGS*)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modi is shown.\n\n`-modi` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modi \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has two parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modi \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modi \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-application-fallback-icon`\n\nSpecify an icon to be used when the application icon in run/drun are not yet loaded or is not available.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modi` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode \n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\n### Combi settings\n\n`-combi-modi` *mode1*,*mode2*\n\nThe modi to combine in combi mode.\nFor syntax to `-combi-modi`, see `-modi`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modi \"window,run,ssh\" -modi combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n### Dmenu specific\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -dmenu -l 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-async-pre-read` *number*\n\nReads the first *number* entries blocking, then switches to async mode.\nThis makes it feel more 'snappy'.\n\n*default*: 25\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal-emulator)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n## DMENU REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\n**rofi** has the following key bindings:\n\n  * `Control-v, Insert`: Paste from clipboard\n  * `Control-Shift-v, Shift-Insert`: Paste primary selection\n  * `Control-u`: Clear the line\n  * `Control-a`: Beginning of line\n  * `Control-e`: End of line\n  * `Control-f, Right`: Forward one character\n  * `Alt-f, Control-Right`: Forward one word\n  * `Control-b, Left`: Back one character\n  * `Alt-b, Control-Left`: Back one word\n  * `Control-d, Delete`: Delete character\n  * `Control-Alt-d`: Delete word\n  * `Control-h, Backspace, Shift-Backspace`: Backspace (delete previous character)\n  * `Control-Alt-h`: Delete previous word\n  * `Control-j,Control-m,Enter`: Accept entry\n  * `Control-n,Down`: Select next entry\n  * `Control-p,Up`: Select previous entry\n  * `Page Up`: Go to previous page\n  * `Page Down`: Go to next page\n  * `Control-Page Up`: Go to previous column\n  * `Control-Page Down`: Go to next column\n  * `Control-Enter`: Use entered text as a command (in `ssh/run modi`)\n  * `Shift-Enter`: Launch the application in a terminal (in run mode)\n  * `Control-Shift-Enter`: As Control-Enter and run the command in terminal (in run mode)\n  * `Shift-Enter`: Return the selected entry and move to the next item while keeping **rofi** open. (in dmenu)\n  * `Shift-Right`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Shift-Left`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-Tab`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Control-Shift-Tab`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-space`: Set selected item as input text.\n  * `Shift-Del`: Delete entry from history.\n  * `grave`: Toggle case sensitivity.\n  * `Alt-grave`: Toggle sorting.\n  * `Alt-Shift-S`: Take a screenshot and store it in the Pictures directory.\n  * `Control-l`: File complete for run dialog.\n\nThis list might not be complete, to get a full list of all key bindings\nsupported in your rofi, see `rofi -h`. The options starting with `-kb` are keybindings.\n\nKey bindings can be modified using the configuration systems. Multiple keys can be bound\nto one action by comma separating them. For example `-kb-primary-paste \"Conctrol+v,Insert\"`\n\nTo get a searchable list of key bindings, run `rofi -show keys`.\n\nA key binding starting with `!` will act when all keys have been released.\n\nYou can bind certain events to key-actions:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n\n## Available Modi\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modi to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modi in one list. Specify which modi are included with the `-combi-modi` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modi.\nAll modi that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modi run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodi are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modi.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font.\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modi run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modi run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modi combi -show combi -combi-modi run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modi combi,window -show combi -combi-modi run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\nUse `qalc` to get a simple calculator in **rofi**:\n\n     rofi -show calc -modi \"calc:qalc +u8 -nocurrencies\"\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://davedavenport.github.io/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nTo debug, it is smart to first try disabling your custom configuration:\n`-no-config`\n\nDisable parsing of configuration. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable them using:\n\n`-no-plugins`\n\nDisables the loading of plugins.\n\nTo further debug the plugin, you can get a trace with (lots of) debug information.  This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G_MESSAGES_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Dialogs.DMenu: The dmenu mode.\n * Dialogs.Run: The run mode.\n * Dialogs.DRun: The desktop file run mode.\n * Dialogs.Window: The window mode.\n * Dialogs.Script: The script mode.\n * Dialogs.Combi: The script mode.\n * Dialogs.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nThe output of this can provide useful information when writing an issue.\n\nMore information (possibly outdated) see [this](https://github.com/DaveDavenport/rofi/wiki/Debugging%20Rofi) wiki entry.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/DaveDavenport/rofi/issues)\n\nWhen creating an issue, please read [this](https://github.com/DaveDavenport/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Quentin Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.2/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable modi.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a list and process the result from user\nactions.  This provide a simple interface to make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modi \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a list of options, separated by a newline\n(`\\n`) (This can be changed by the script).\nIf the user selects an option, rofi calls the executable with the text of that option as the first argument.\nIf the script returns no entries, rofi quits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nQuentin Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.2/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## DEFAULT THEME LOADING\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nIn the default (always loaded) configuration it does:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add `@theme` to your\n`config.rasi` file.\n\nIf you have a theme loaded by `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is utf-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with a hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path should always start with a `#`.\nMultiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly inherited from their parent with the\n`inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox` is a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the highlighted text.\n * `strikethrough`: put a line through the highlighted text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\nIt supports the following operations:\n\n* `+`   : Add\n* `-`   : Subtract\n* `/`   : Divide\n* `*`   : Multiply\n* `%`   : Multiply\n* `min` : Minimum of l or rvalue;\n* `max` : Maximum of l or rvalue;\n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n## Position\n\nIndicate a place on the window/monitor.\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n```\n\nnorth west   |    north    |  north east\n-------------|-------------|------------\n      west   |   center    |  east\n-------------|-------------|------------\nsouth west   |    south    |  south east\n```\n\n## Visibility\n\nIt is possible to hide widgets:\n\ninputbar {\n    enabled: false;\n}\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n* Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the property\n`width` is not set, the default value is used.\n\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n* Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\nIf the environment value is not found, the default value is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default value (`40%`).\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:         enable/disable the widget\n* **padding**:         padding\n  Padding on the inside of the widget\n* **margin**:          padding\n  Margin on the outside of the widget\n* **border**:          border\n  Border around the widget (between padding and margin)/\n* **border-radius**:    padding\n  Sets a radius on the corners of the borders.\n* **background-color**:      color\n  Background color\n* **background-image**:      image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:      cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:  distance\n* **y-offset**:  distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:         distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**:               the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n|------------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                              |\n| |-------------------------------------------------------------------------------|  |\n| | mainbox  {BOX:vertical}                                                       |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | inputbar {BOX:horizontal}                                                 | |  |\n| | | |---------| |-| |---------------------------------|---| |---| |---| |---| | |  |\n| | | | prompt  | |:| | entry                           |#fr| | / | |#ns| |ci | | |  |\n| | | |---------| |_| |---------------------------------|---| |---| |---| |---| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | message                                                                   | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | | | textbox                                                               | | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |-----------------------------------------------------------------------------|  |\n| | | listview                                                                    |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | | | element                                                                |  |  |\n| | | | |-----------------| |------------------------------------------------] |  |  |\n| | | | |element-icon     | |element-text                                    | |  |  |\n| | | | |-----------------| |------------------------------------------------| |  |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | |-----------------------------------------------------------------------------|  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | |  mode-switcher {BOX:horizontal}                                           | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | | | Button        |   | Button        |  | Button       | | Button        | | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |-------------------------------------------------------------------------------|  |\n|------------------------------------------------------------------------------------|\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n|-----------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                             |\n| |------------------------------------------------------------------------------|  |\n| | error-message {BOX:vertical}                                                 |  |\n| | |-------------------------------------------------------------------------|  |  |\n| | | textbox                                                                 |  |  |\n| | |-------------------------------------------------------------------------|  |  |\n| |------------------------------------------------------------------------------|  |\n|-----------------------------------------------------------------------------------|\n\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n|-------------------------------------------------------------------|\n| margin                                                            |\n|  |-------------------------------------------------------------|  |\n|  | border                                                      |  |\n|  | |---------------------------------------------------------| |  |\n|  | | padding                                                 | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | | | content                                             | | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | |---------------------------------------------------------| |  |\n|  |-------------------------------------------------------------|  |\n|-------------------------------------------------------------------|\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n|---------------------------------------|\n|  |--------| s |--------| s |-------|  |\n|  | child  | p | child  | p | child |  |\n|  |        | a |        | a |       |  |\n|  |        | c |        | c |       |  |\n|  |        | i |        | i |       |  |\n|  |        | n |        | n |       |  |\n|  |--------| g |--------| g |-------|  |\n|---------------------------------------|\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n|----------------------------------------------------|\n|  |---------------|  |--------|  |---------------|  |\n|  | dummy         |  | child  |  | dummy         |  |\n|  | expand: true; |  |        |  | expand: true; |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |---------------|  |--------|  |---------------|  |\n|----------------------------------------------------|\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.2/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and more. It focuses on\nbeing fast to use and have minimal distraction. It supports keyboard and mouse navigation, type to\nfilter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to quickly switch\nbetween windows, start applications or log into a remote machine via `ssh`.\nThere are different *modi* for different types of actions.\n\n**rofi** can also function as (drop-in) replacement for **dmenu(1)**.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `run` dialog:\n\n    rofi -show run\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with the `-dmenu` flag.\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set values.\nThese include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`, `ssh`, `combi`.\nThe special argument `keys` can be used to open a searchable list of supported key bindings\n(see *KEY BINDINGS*)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modi is shown.\n\n`-modi` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modi \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has two parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modi \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modi \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-application-fallback-icon`\n\nSpecify an icon to be used when the application icon in run/drun are not yet loaded or is not available.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modi` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode \n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\n### Combi settings\n\n`-combi-modi` *mode1*,*mode2*\n\nThe modi to combine in combi mode.\nFor syntax to `-combi-modi`, see `-modi`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modi \"window,run,ssh\" -modi combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n### Dmenu specific\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -dmenu -l 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-async-pre-read` *number*\n\nReads the first *number* entries blocking, then switches to async mode.\nThis makes it feel more 'snappy'.\n\n*default*: 25\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal-emulator)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n## DMENU REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\n**rofi** has the following key bindings:\n\n  * `Control-v, Insert`: Paste from clipboard\n  * `Control-Shift-v, Shift-Insert`: Paste primary selection\n  * `Control-u`: Clear the line\n  * `Control-a`: Beginning of line\n  * `Control-e`: End of line\n  * `Control-f, Right`: Forward one character\n  * `Alt-f, Control-Right`: Forward one word\n  * `Control-b, Left`: Back one character\n  * `Alt-b, Control-Left`: Back one word\n  * `Control-d, Delete`: Delete character\n  * `Control-Alt-d`: Delete word\n  * `Control-h, Backspace, Shift-Backspace`: Backspace (delete previous character)\n  * `Control-Alt-h`: Delete previous word\n  * `Control-j,Control-m,Enter`: Accept entry\n  * `Control-n,Down`: Select next entry\n  * `Control-p,Up`: Select previous entry\n  * `Page Up`: Go to previous page\n  * `Page Down`: Go to next page\n  * `Control-Page Up`: Go to previous column\n  * `Control-Page Down`: Go to next column\n  * `Control-Enter`: Use entered text as a command (in `ssh/run modi`)\n  * `Shift-Enter`: Launch the application in a terminal (in run mode)\n  * `Control-Shift-Enter`: As Control-Enter and run the command in terminal (in run mode)\n  * `Shift-Enter`: Return the selected entry and move to the next item while keeping **rofi** open. (in dmenu)\n  * `Shift-Right`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Shift-Left`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-Tab`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Control-Shift-Tab`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-space`: Set selected item as input text.\n  * `Shift-Del`: Delete entry from history.\n  * `grave`: Toggle case sensitivity.\n  * `Alt-grave`: Toggle sorting.\n  * `Alt-Shift-S`: Take a screenshot and store it in the Pictures directory.\n  * `Control-l`: File complete for run dialog.\n\nThis list might not be complete, to get a full list of all key bindings\nsupported in your rofi, see `rofi -h`. The options starting with `-kb` are keybindings.\n\nKey bindings can be modified using the configuration systems. Multiple keys can be bound\nto one action by comma separating them. For example `-kb-primary-paste \"Conctrol+v,Insert\"`\n\nTo get a searchable list of key bindings, run `rofi -show keys`.\n\nA key binding starting with `!` will act when all keys have been released.\n\nYou can bind certain events to key-actions:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n\n## Available Modi\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modi to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modi in one list. Specify which modi are included with the `-combi-modi` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modi.\nAll modi that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modi run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodi are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modi.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font.\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modi run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modi run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modi combi -show combi -combi-modi run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modi combi,window -show combi -combi-modi run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\nUse `qalc` to get a simple calculator in **rofi**:\n\n     rofi -show calc -modi \"calc:qalc +u8 -nocurrencies\"\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://davedavenport.github.io/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nTo debug, it is smart to first try disabling your custom configuration:\n`-no-config`\n\nDisable parsing of configuration. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable them using:\n\n`-no-plugins`\n\nDisables the loading of plugins.\n\nTo further debug the plugin, you can get a trace with (lots of) debug information.  This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G_MESSAGES_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Dialogs.DMenu: The dmenu mode.\n * Dialogs.Run: The run mode.\n * Dialogs.DRun: The desktop file run mode.\n * Dialogs.Window: The window mode.\n * Dialogs.Script: The script mode.\n * Dialogs.Combi: The script mode.\n * Dialogs.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nThe output of this can provide useful information when writing an issue.\n\nMore information (possibly outdated) see [this](https://github.com/DaveDavenport/rofi/wiki/Debugging%20Rofi) wiki entry.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/DaveDavenport/rofi/issues)\n\nWhen creating an issue, please read [this](https://github.com/DaveDavenport/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Quentin Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi-debugging.5.markdown",
    "content": "# ROFI DEBUGGING 5 rofi debugging\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some small test\nto help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact version, monitor layout\nand more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\n\nIt will show a trace with (useful) timing information at relevant points during the execution.\nThis will help debugging when rofi is slow to start.\n\nExample trace:\n\n```\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug information. This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G\\_MESSAGES\\_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Modes.DMenu: The dmenu mode.\n * Modes.Run: The run mode.\n * Modes.DRun: The desktop file run mode.\n * Modes.Window: The window mode.\n * Modes.Script: The script mode.\n * Modes.Combi: The script mode.\n * Modes.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output from the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n\n## Creating a backtrace.\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it grabs keyboard and\nmouse. So if it crashes in GDB you are stuck.\nThe best way to go is to enable core file. (ulimit -c unlimited in bash) then make rofi crash. You\ncan then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a backtrace via `coredumpctl`.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi-dmenu.5.markdown",
    "content": "# ROFI-DMENU 5 rofi-dmenu\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into separate entries and displays them.\nIf the user selects an row, this is printed out to standard out, allow the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the output a one application into \n**rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation mode.\n\n```bash\nls | rofi -dmenu\n```\n\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the **rofi-script(5)** manpage for more information.\n\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input. See the **rofi-script(5)** manpage\nfor more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -dmenu -l 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-async-pre-read` *number*\n\nReads the first *number* entries blocking, then switches to async mode.\nThis makes it feel more 'snappy'.\n\n*default*: 25\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n\n## RETURN VALUE\n\n * **0**: Row has been selected accepted by user.\n * **1**: User cancelled the selection.\n * **10-28**: Row accepted by custom keybinding.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi-keys.5.markdown",
    "content": "# ROFI-KEYS 5 rofi-keys\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings \n\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n\n## Keyboard Bindings\n\n### **kb-primary-paste**:\nPaste primary selection\n\n  **Default**: \tControl+V,Shift+Insert \n\n### **kb-secondary-paste**\nPaste clipboard\n\n**Default**: \tControl+v,Insert \n\n### **kb-clear-line**\nClear input line\n\n**Default**: \tControl+w \n\n### **kb-move-front**\nBeginning of line\n\n**Default**: \tControl+a \n\n### **kb-move-end**\nEnd of line\n\n**Default**: \tControl+e \n\n### **kb-move-word-back**\nMove back one word\n\n**Default**: \tAlt+b,Control+Left \n\n### **kb-move-word-forward**\nMove forward one word\n\n**Default**: \tAlt+f,Control+Right \n\n### **kb-move-char-back**\nMove back one char\n\n**Default**: \tLeft,Control+b \n\n### **kb-move-char-forward**\nMove forward one char\n\n**Default**: \tRight,Control+f \n\n### **kb-remove-word-back**\nDelete previous word\n\n**Default**: \tControl+Alt+h,Control+BackSpace \n\n### **kb-remove-word-forward**\nDelete next word\n\n**Default**: \tControl+Alt+d \n\n### **kb-remove-char-forward**\nDelete next char\n\n**Default**: \tDelete,Control+d \n\n### **kb-remove-char-back**\nDelete previous char\n\n**Default**: \tBackSpace,Shift+BackSpace,Control+h \n\n### **kb-remove-to-eol**\nDelete till the end of line\n\n**Default**: \tControl+k \n\n### **kb-remove-to-sol**\nDelete till the start of line\n\n**Default**: \tControl+u \n\n### **kb-accept-entry**\nAccept entry\n\n**Default**: \tControl+j,Control+m,Return,KP_Enter \n\n### **kb-accept-custom**\nUse entered text as command (in ssh/run modi)\n\n**Default**: \tControl+Return \n\n### **kb-accept-custom-alt**\nUse entered text as command (in ssh/run modi)\n\n**Default**: \tControl+Shift+Return \n\n### **kb-accept-alt**\nUse alternate accept command.\n\n**Default**: \tShift+Return \n\n### **kb-delete-entry**\nDelete entry from history\n\n**Default**: \tShift+Delete \n\n### **kb-mode-next**\nSwitch to the next mode.\n\n**Default**: \tShift+Right,Control+Tab \n\n### **kb-mode-previous**\nSwitch to the previous mode.\n\n**Default**: \tShift+Left,Control+ISO_Left_Tab \n\n### **kb-mode-complete**\nStart completion for mode.\n\n**Default**: \tControl+l \n\n### **kb-row-left**\nGo to the previous column\n\n**Default**: \tControl+Page_Up \n\n### **kb-row-right**\nGo to the next column\n\n**Default**: \tControl+Page_Down \n\n### **kb-row-up**\nSelect previous entry\n\n**Default**: \tUp,Control+p,ISO_Left_Tab \n\n### **kb-row-down**\nSelect next entry\n\n**Default**: \tDown,Control+n \n\n### **kb-row-tab**\nGo to next row, if one left, accept it, if no left next mode.\n\n**Default**: \tTab \n\n### **kb-page-prev**\nGo to the previous page\n\n**Default**: \tPage_Up \n\n### **kb-page-next**\nGo to the next page\n\n**Default**: \tPage_Down \n\n### **kb-row-first**\nGo to the first entry\n\n**Default**: \tHome,KP_Home \n\n### **kb-row-last**\nGo to the last entry\n\n**Default**: \tEnd,KP_End \n\n### **kb-row-select**\nSet selected item as input text\n\n**Default**: \tControl+space \n\n### **kb-screenshot**\nTake a screenshot of the rofi window\n\n**Default**: \tAlt+S \n\n### **kb-ellipsize**\nToggle between ellipsize modes for displayed data\n\n**Default**: \tAlt+period \n\n### **kb-toggle-case-sensitivity**\nToggle case sensitivity\n\n**Default**: \tgrave,dead_grave \n\n### **kb-toggle-sort**\nToggle sort\n\n**Default**: \tAlt+grave \n\n### **kb-cancel**\nQuit rofi\n\n**Default**: \tEscape,Control+g,Control+bracketleft \n\n### **kb-custom-1**\nCustom keybinding 1\n\n**Default**: \tAlt+1 \n\n### **kb-custom-2**\nCustom keybinding 2\n\n**Default**: \tAlt+2 \n\n### **kb-custom-3**\nCustom keybinding 3\n\n**Default**: \tAlt+3 \n\n### **kb-custom-4**\nCustom keybinding 4\n\n**Default**: \tAlt+4 \n\n### **kb-custom-5**\nCustom Keybinding 5\n\n**Default**: \tAlt+5 \n\n### **kb-custom-6**\nCustom keybinding 6\n\n**Default**: \tAlt+6 \n\n### **kb-custom-7**\nCustom Keybinding 7\n\n**Default**: \tAlt+7 \n\n### **kb-custom-8**\nCustom keybinding 8\n\n**Default**: \tAlt+8 \n\n### **kb-custom-9**\nCustom keybinding 9\n\n**Default**: \tAlt+9 \n\n### **kb-custom-10**\nCustom keybinding 10\n\n**Default**: \tAlt+0 \n\n### **kb-custom-11**\nCustom keybinding 11\n\n**Default**: \tAlt+exclam \n\n### **kb-custom-12**\nCustom keybinding 12\n\n**Default**: \tAlt+at \n\n### **kb-custom-13**\nCustom keybinding 13\n\n**Default**: \tAlt+numbersign \n\n### **kb-custom-14**\nCustom keybinding 14\n\n**Default**: \tAlt+dollar \n\n### **kb-custom-15**\nCustom keybinding 15\n\n**Default**: \tAlt+percent \n\n### **kb-custom-16**\nCustom keybinding 16\n\n**Default**: \tAlt+dead_circumflex \n\n### **kb-custom-17**\nCustom keybinding 17\n\n**Default**: \tAlt+ampersand \n\n### **kb-custom-18**\nCustom keybinding 18\n\n**Default**: \tAlt+asterisk \n\n### **kb-custom-19**\nCustom Keybinding 19\n\n**Default**: \tAlt+parenleft \n\n### **kb-select-1**\nSelect row 1\n\n**Default**: \tSuper+1 \n\n### **kb-select-2**\nSelect row 2\n\n**Default**: \tSuper+2 \n\n### **kb-select-3**\nSelect row 3\n\n**Default**: \tSuper+3 \n\n### **kb-select-4**\nSelect row 4\n\n**Default**: \tSuper+4 \n\n### **kb-select-5**\nSelect row 5\n\n**Default**: \tSuper+5 \n\n### **kb-select-6**\nSelect row 6\n\n**Default**: \tSuper+6 \n\n### **kb-select-7**\nSelect row 7\n\n**Default**: \tSuper+7 \n\n### **kb-select-8**\nSelect row 8\n\n**Default**: \tSuper+8 \n\n### **kb-select-9**\nSelect row 9\n\n**Default**: \tSuper+9 \n\n### **kb-select-10**\nSelect row 10\n\n**Default**: \tSuper+0 \n\n## Mouse Bindings\n\n### **ml-row-left**\nGo to the previous column\n\n**Default**: \tScrollLeft \n\n### **ml-row-right**\nGo to the next column\n\n**Default**: \tScrollRight \n\n### **ml-row-up**\nSelect previous entry\n\n**Default**: \tScrollUp \n\n### **ml-row-down**\nSelect next entry\n\n**Default**: \tScrollDown \n\n### **me-select-entry**\nSelect hovered row\n\n **Default**: \tMousePrimary \n\n### **me-accept-entry**\nAccept hovered row\n\n**Default**: \tMouseDPrimary \n\n### **me-accept-custom**\nAccept hovered row with custom action\n\n**Default**: \tControl+MouseDPrimary \n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5) \n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable modi.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a list and process the result from user\nactions.  This provide a simple interface to make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modi \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a list of options, separated by a newline\n(`\\n`) (This can be changed by the script).\nIf the user selects an option, rofi calls the executable with the text of that option as the first argument.\nIf the script returns no entries, rofi quits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## DEFAULT THEME LOADING\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nIn the default (always loaded) configuration it does:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add `@theme` to your\n`config.rasi` file.\n\nIf you have a theme loaded by `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is utf-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with a hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path should always start with a `#`.\nMultiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly inherited from their parent with the\n`inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox` is a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an array of values\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the highlighted text.\n * `strikethrough`: put a line through the highlighted text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\nIt supports the following operations:\n\n* `+`   : Add\n* `-`   : Subtract\n* `/`   : Divide\n* `*`   : Multiply\n* `%`   : Multiply\n* `min` : Minimum of l or rvalue;\n* `max` : Maximum of l or rvalue;\n* `floor` : Round down lvalue to the next multiple of rvalue \n* `ceil` : Round up lvalue to the next multiple of rvalue \n* `round` : Round lvalue to the next multiple of rvalue \n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n\n## Position\n\nIndicate a place on the window/monitor.\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n```\n\nnorth west   |    north    |  north east\n-------------|-------------|------------\n      west   |   center    |  east\n-------------|-------------|------------\nsouth west   |    south    |  south east\n```\n\n## Visibility\n\nIt is possible to hide widgets:\n\ninputbar {\n    enabled: false;\n}\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n* Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the property\n`width` is not set, the default value is used.\n\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## List of values\n\n* Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n* Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\nIf the environment value is not found, the default value is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default value (`40%`).\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:         enable/disable the widget\n* **padding**:         padding\n  Padding on the inside of the widget\n* **margin**:          padding\n  Margin on the outside of the widget\n* **border**:          border\n  Border around the widget (between padding and margin)/\n* **border-radius**:    padding\n  Sets a radius on the corners of the borders.\n* **background-color**:      color\n  Background color\n* **background-image**:      image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:      cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:  distance\n* **y-offset**:  distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:         distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**:               the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n* **tab-stops**:         array of distances\n    Set the location of tab stops by their distance from the beginning of the line.\n    Each distance should be greater than the previous one.\n    The text appears to the right of the tab stop position (other alignments are not supported yet).\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n|------------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                              |\n| |-------------------------------------------------------------------------------|  |\n| | mainbox  {BOX:vertical}                                                       |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | inputbar {BOX:horizontal}                                                 | |  |\n| | | |---------| |-| |---------------------------------|---| |---| |---| |---| | |  |\n| | | | prompt  | |:| | entry                           |#fr| | / | |#ns| |ci | | |  |\n| | | |---------| |_| |---------------------------------|---| |---| |---| |---| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | | message                                                                   | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | | | textbox                                                               | | |  |\n| | | |-----------------------------------------------------------------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |                                                                               |  |\n| | |-----------------------------------------------------------------------------|  |\n| | | listview                                                                    |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | | | element                                                                |  |  |\n| | | | |-----------------| |------------------------------------------------] |  |  |\n| | | | |element-icon     | |element-text                                    | |  |  |\n| | | | |-----------------| |------------------------------------------------| |  |  |\n| | | |------------------------------------------------------------------------]  |  |\n| | |-----------------------------------------------------------------------------|  |\n| |                                                                               |  |\n| | |---------------------------------------------------------------------------| |  |\n| | |  mode-switcher {BOX:horizontal}                                           | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | | | Button        |   | Button        |  | Button       | | Button        | | |  |\n| | | |---------------|   |---------------|  |--------------| |---------------| | |  |\n| | |---------------------------------------------------------------------------| |  |\n| |-------------------------------------------------------------------------------|  |\n|------------------------------------------------------------------------------------|\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n|-----------------------------------------------------------------------------------|\n| window {BOX:vertical}                                                             |\n| |------------------------------------------------------------------------------|  |\n| | error-message {BOX:vertical}                                                 |  |\n| | |-------------------------------------------------------------------------|  |  |\n| | | textbox                                                                 |  |  |\n| | |-------------------------------------------------------------------------|  |  |\n| |------------------------------------------------------------------------------|  |\n|-----------------------------------------------------------------------------------|\n\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n|-------------------------------------------------------------------|\n| margin                                                            |\n|  |-------------------------------------------------------------|  |\n|  | border                                                      |  |\n|  | |---------------------------------------------------------| |  |\n|  | | padding                                                 | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | | | content                                             | | |  |\n|  | | |-----------------------------------------------------| | |  |\n|  | |---------------------------------------------------------| |  |\n|  |-------------------------------------------------------------|  |\n|-------------------------------------------------------------------|\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n|---------------------------------------|\n|  |--------| s |--------| s |-------|  |\n|  | child  | p | child  | p | child |  |\n|  |        | a |        | a |       |  |\n|  |        | c |        | c |       |  |\n|  |        | i |        | i |       |  |\n|  |        | n |        | n |       |  |\n|  |--------| g |--------| g |-------|  |\n|---------------------------------------|\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n|----------------------------------------------------|\n|  |---------------|  |--------|  |---------------|  |\n|  | dummy         |  | child  |  | dummy         |  |\n|  | expand: true; |  |        |  | expand: true; |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |               |  |        |  |               |  |\n|  |---------------|  |--------|  |---------------|  |\n|----------------------------------------------------|\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.3/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and more. It focuses on\nbeing fast to use and have minimal distraction. It supports keyboard and mouse navigation, type to\nfilter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to quickly switch\nbetween windows, start applications or log into a remote machine via `ssh`.\nThere are different *modi* for different types of actions.\n**rofi** is a standalone application and should not be integrated into scripts.\nFor integration into scripts it has a special mode that functions as a\n(drop-in) replacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `run` dialog:\n\n    rofi -show run\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with the `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set values.\nThese include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`, `ssh`, `combi`.\nThe special argument `keys` can be used to open a searchable list of supported key bindings\n(see *KEY BINDINGS*)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modi is shown.\n\n`-modi` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modi \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has two parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modi \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modi \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-application-fallback-icon`\n\nSpecify an icon to be used when the application icon in run/drun are not yet loaded or is not available.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modi` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode \n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\n### Combi settings\n\n`-combi-modi` *mode1*,*mode2*\n\nThe modi to combine in combi mode.\nFor syntax to `-combi-modi`, see `-modi`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modi \"window,run,ssh\" -modi combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n* **mode**: the mode display name\n* **text**: the entry text\n\nPango markup can be used to formatting the output.\n\n    Default: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is eanbled.\n\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\n**rofi** has the following key bindings:\n\n  * `Control-v, Insert`: Paste from clipboard\n  * `Control-Shift-v, Shift-Insert`: Paste primary selection\n  * `Control-u`: Clear the line\n  * `Control-a`: Beginning of line\n  * `Control-e`: End of line\n  * `Control-f, Right`: Forward one character\n  * `Alt-f, Control-Right`: Forward one word\n  * `Control-b, Left`: Back one character\n  * `Alt-b, Control-Left`: Back one word\n  * `Control-d, Delete`: Delete character\n  * `Control-Alt-d`: Delete word\n  * `Control-h, Backspace, Shift-Backspace`: Backspace (delete previous character)\n  * `Control-Alt-h`: Delete previous word\n  * `Control-j,Control-m,Enter`: Accept entry\n  * `Control-n,Down`: Select next entry\n  * `Control-p,Up`: Select previous entry\n  * `Page Up`: Go to previous page\n  * `Page Down`: Go to next page\n  * `Control-Page Up`: Go to previous column\n  * `Control-Page Down`: Go to next column\n  * `Control-Enter`: Use entered text as a command (in `ssh/run modi`)\n  * `Shift-Enter`: Launch the application in a terminal (in run mode)\n  * `Control-Shift-Enter`: As Control-Enter and run the command in terminal (in run mode)\n  * `Shift-Enter`: Return the selected entry and move to the next item while keeping **rofi** open. (in dmenu)\n  * `Shift-Right`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Shift-Left`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-Tab`: Switch to the next mode. The list can be customized with the `-modi` argument.\n  * `Control-Shift-Tab`: Switch to the previous mode. The list can be customized with the `-modi` argument.\n  * `Control-space`: Set selected item as input text.\n  * `Shift-Del`: Delete entry from history.\n  * `grave`: Toggle case sensitivity.\n  * `Alt-grave`: Toggle sorting.\n  * `Alt-Shift-S`: Take a screenshot and store it in the Pictures directory.\n  * `Control-l`: File complete for run dialog.\n\nThis list might not be complete, to get a full list of all key bindings\nsupported in your rofi, see `rofi -h`. The options starting with `-kb` are keybindings.\n\nKey bindings can be modified using the configuration systems. Multiple keys can be bound\nto one action by comma separating them. For example `-kb-primary-paste \"Conctrol+v,Insert\"`\n\nTo get a searchable list of key bindings, run `rofi -show keys`.\n\nA key binding starting with `!` will act when all keys have been released.\n\nYou can bind certain events to key-actions:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\nFor a full list of bindings, see the **rofi-keys(5)** manpage.\n\n## Available Modi\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modi to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modi in one list. Specify which modi are included with the `-combi-modi` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modi.\nAll modi that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modi run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodi are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modi.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font.\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n* Window: It first uses the icon that the application exposes via the X11\n  Server, if none is set it does a lookup of the window Class name in the icon theme.\n* drun: It uses the icon set in the desktop file.\n* run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modi run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modi run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modi combi -show combi -combi-modi run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modi combi,window -show combi -combi-modi run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\nUse `qalc` to get a simple calculator in **rofi**:\n\n     rofi -show calc -modi \"calc:qalc +u8 -nocurrencies\"\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://davedavenport.github.io/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nTo debug, it is smart to first try disabling your custom configuration:\n`-no-config`\n\nDisable parsing of configuration. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable them using:\n\n`-no-plugins`\n\nDisables the loading of plugins.\n\nTo further debug the plugin, you can get a trace with (lots of) debug information.  This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G_MESSAGES_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Dialogs.DMenu: The dmenu mode.\n * Dialogs.Run: The run mode.\n * Dialogs.DRun: The desktop file run mode.\n * Dialogs.Window: The window mode.\n * Dialogs.Script: The script mode.\n * Dialogs.Combi: The script mode.\n * Dialogs.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nThe output of this can provide useful information when writing an issue.\n\nMore information (possibly outdated) see [this](https://github.com/DaveDavenport/rofi/wiki/Debugging%20Rofi) wiki entry.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/DaveDavenport/rofi/issues)\n\nWhen creating an issue, please read [this](https://github.com/DaveDavenport/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi-debugging.5.markdown",
    "content": "# ROFI DEBUGGING 5 rofi debugging\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some small test\nto help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact version, monitor layout\nand more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\n\nIt will show a trace with (useful) timing information at relevant points during the execution.\nThis will help debugging when rofi is slow to start.\n\nExample trace:\n\n```\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug information. This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G\\_MESSAGES\\_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Modes.DMenu: The dmenu mode.\n * Modes.Run: The run mode.\n * Modes.DRun: The desktop file run mode.\n * Modes.Window: The window mode.\n * Modes.Script: The script mode.\n * Modes.Combi: The script mode.\n * Modes.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output from the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n\n## Creating a backtrace.\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it grabs keyboard and\nmouse. So if it crashes in GDB you are stuck.\nThe best way to go is to enable core file. (ulimit -c unlimited in bash) then make rofi crash. You\ncan then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a backtrace via `coredumpctl`.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi-dmenu.5.markdown",
    "content": "# ROFI-DMENU 5 rofi-dmenu\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into separate entries and displays them.\nIf the user selects an row, this is printed out to standard out, allow the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the output a one application into \n**rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation mode.\n\n```bash\nls | rofi -dmenu\n```\n\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the **rofi-script(5)** manpage for more information.\n\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input. See the **rofi-script(5)** manpage\nfor more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -dmenu -l 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n## RETURN VALUE\n\n * **0**: Row has been selected accepted by user.\n * **1**: User cancelled the selection.\n * **10-28**: Row accepted by custom keybinding.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5), rofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi-keys.5.markdown",
    "content": "# ROFI-KEYS 5 rofi-keys\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings \n\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n\n## Keyboard Bindings\n\n### **kb-primary-paste**:\nPaste primary selection\n\n  **Default**: \tControl+V,Shift+Insert \n\n### **kb-secondary-paste**\nPaste clipboard\n\n**Default**: \tControl+v,Insert \n\n### **kb-clear-line**\nClear input line\n\n**Default**: \tControl+w \n\n### **kb-move-front**\nBeginning of line\n\n**Default**: \tControl+a \n\n### **kb-move-end**\nEnd of line\n\n**Default**: \tControl+e \n\n### **kb-move-word-back**\nMove back one word\n\n**Default**: \tAlt+b,Control+Left \n\n### **kb-move-word-forward**\nMove forward one word\n\n**Default**: \tAlt+f,Control+Right \n\n### **kb-move-char-back**\nMove back one char\n\n**Default**: \tLeft,Control+b \n\n### **kb-move-char-forward**\nMove forward one char\n\n**Default**: \tRight,Control+f \n\n### **kb-remove-word-back**\nDelete previous word\n\n**Default**: \tControl+Alt+h,Control+BackSpace \n\n### **kb-remove-word-forward**\nDelete next word\n\n**Default**: \tControl+Alt+d \n\n### **kb-remove-char-forward**\nDelete next char\n\n**Default**: \tDelete,Control+d \n\n### **kb-remove-char-back**\nDelete previous char\n\n**Default**: \tBackSpace,Shift+BackSpace,Control+h \n\n### **kb-remove-to-eol**\nDelete till the end of line\n\n**Default**: \tControl+k \n\n### **kb-remove-to-sol**\nDelete till the start of line\n\n**Default**: \tControl+u \n\n### **kb-accept-entry**\nAccept entry\n\n**Default**: \tControl+j,Control+m,Return,KP_Enter \n\n### **kb-accept-custom**\nUse entered text as command (in ssh/run modes)\n\n**Default**: \tControl+Return \n\n### **kb-accept-custom-alt**\nUse entered text as command (in ssh/run modes)\n\n**Default**: \tControl+Shift+Return \n\n### **kb-accept-alt**\nUse alternate accept command.\n\n**Default**: \tShift+Return \n\n### **kb-delete-entry**\nDelete entry from history\n\n**Default**: \tShift+Delete \n\n### **kb-mode-next**\nSwitch to the next mode.\n\n**Default**: \tShift+Right,Control+Tab \n\n### **kb-mode-previous**\nSwitch to the previous mode.\n\n**Default**: \tShift+Left,Control+ISO_Left_Tab \n\n### **kb-mode-complete**\nStart completion for mode.\n\n**Default**: \tControl+l \n\n### **kb-row-left**\nGo to the previous column\n\n**Default**: \tControl+Page_Up \n\n### **kb-row-right**\nGo to the next column\n\n**Default**: \tControl+Page_Down \n\n### **kb-row-up**\nSelect previous entry\n\n**Default**: \tUp,Control+p \n\n### **kb-row-down**\nSelect next entry\n\n**Default**: \tDown,Control+n \n\n### **kb-row-tab**\nGo to next row, if one left, accept it, if no left next mode.\n\n**Default**: \t\n\n### **kb-element-next**\nGo to next row.\n\n**Default**: Tab\t\n\n### **kb-element-prev**\nGo to previous row.\n\n**Default**: ISO_Left_Tab\n\n### **kb-page-prev**\nGo to the previous page\n\n**Default**: \tPage_Up \n\n### **kb-page-next**\nGo to the next page\n\n**Default**: \tPage_Down \n\n### **kb-row-first**\nGo to the first entry\n\n**Default**: \tHome,KP_Home \n\n### **kb-row-last**\nGo to the last entry\n\n**Default**: \tEnd,KP_End \n\n### **kb-row-select**\nSet selected item as input text\n\n**Default**: \tControl+space \n\n### **kb-screenshot**\nTake a screenshot of the rofi window\n\n**Default**: \tAlt+S \n\n### **kb-ellipsize**\nToggle between ellipsize modes for displayed data\n\n**Default**: \tAlt+period \n\n### **kb-toggle-case-sensitivity**\nToggle case sensitivity\n\n**Default**: \tgrave,dead_grave \n\n### **kb-toggle-sort**\nToggle sort\n\n**Default**: \tAlt+grave \n\n### **kb-cancel**\nQuit rofi\n\n**Default**: \tEscape,Control+g,Control+bracketleft \n\n### **kb-custom-1**\nCustom keybinding 1\n\n**Default**: \tAlt+1 \n\n### **kb-custom-2**\nCustom keybinding 2\n\n**Default**: \tAlt+2 \n\n### **kb-custom-3**\nCustom keybinding 3\n\n**Default**: \tAlt+3 \n\n### **kb-custom-4**\nCustom keybinding 4\n\n**Default**: \tAlt+4 \n\n### **kb-custom-5**\nCustom Keybinding 5\n\n**Default**: \tAlt+5 \n\n### **kb-custom-6**\nCustom keybinding 6\n\n**Default**: \tAlt+6 \n\n### **kb-custom-7**\nCustom Keybinding 7\n\n**Default**: \tAlt+7 \n\n### **kb-custom-8**\nCustom keybinding 8\n\n**Default**: \tAlt+8 \n\n### **kb-custom-9**\nCustom keybinding 9\n\n**Default**: \tAlt+9 \n\n### **kb-custom-10**\nCustom keybinding 10\n\n**Default**: \tAlt+0 \n\n### **kb-custom-11**\nCustom keybinding 11\n\n**Default**: \tAlt+exclam \n\n### **kb-custom-12**\nCustom keybinding 12\n\n**Default**: \tAlt+at \n\n### **kb-custom-13**\nCustom keybinding 13\n\n**Default**: \tAlt+numbersign \n\n### **kb-custom-14**\nCustom keybinding 14\n\n**Default**: \tAlt+dollar \n\n### **kb-custom-15**\nCustom keybinding 15\n\n**Default**: \tAlt+percent \n\n### **kb-custom-16**\nCustom keybinding 16\n\n**Default**: \tAlt+dead_circumflex \n\n### **kb-custom-17**\nCustom keybinding 17\n\n**Default**: \tAlt+ampersand \n\n### **kb-custom-18**\nCustom keybinding 18\n\n**Default**: \tAlt+asterisk \n\n### **kb-custom-19**\nCustom Keybinding 19\n\n**Default**: \tAlt+parenleft \n\n### **kb-select-1**\nSelect row 1\n\n**Default**: \tSuper+1 \n\n### **kb-select-2**\nSelect row 2\n\n**Default**: \tSuper+2 \n\n### **kb-select-3**\nSelect row 3\n\n**Default**: \tSuper+3 \n\n### **kb-select-4**\nSelect row 4\n\n**Default**: \tSuper+4 \n\n### **kb-select-5**\nSelect row 5\n\n**Default**: \tSuper+5 \n\n### **kb-select-6**\nSelect row 6\n\n**Default**: \tSuper+6 \n\n### **kb-select-7**\nSelect row 7\n\n**Default**: \tSuper+7 \n\n### **kb-select-8**\nSelect row 8\n\n**Default**: \tSuper+8 \n\n### **kb-select-9**\nSelect row 9\n\n**Default**: \tSuper+9 \n\n### **kb-select-10**\nSelect row 10\n\n**Default**: \tSuper+0 \n\n## Mouse Bindings\n\n### **ml-row-left**\nGo to the previous column\n\n**Default**: \tScrollLeft \n\n### **ml-row-right**\nGo to the next column\n\n**Default**: \tScrollRight \n\n### **ml-row-up**\nSelect previous entry\n\n**Default**: \tScrollUp \n\n### **ml-row-down**\nSelect next entry\n\n**Default**: \tScrollDown \n\n### **me-select-entry**\nSelect hovered row\n\n **Default**: \tMousePrimary \n\n### **me-accept-entry**\nAccept hovered row\n\n**Default**: \tMouseDPrimary \n\n### **me-accept-custom**\nAccept hovered row with custom action\n\n**Default**: \tControl+MouseDPrimary \n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5) \n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n * **keep-selection**: If set, the selection is not moved to the first entry, but the current position is maintained. The filter is cleared.\n * **new-selection**: If `keep-selection` is set, this allows you to override the selected entry (absolute position). \n * **data**:         Passed data to the next execution of the script via **ROFI_DATA**.\n * **theme**:       Small theme snippet to f.e. change the background color of a widget.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## GETTING STARTED WITH THEMING \n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the  \nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`.\nTo find the commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text` widget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## DEFAULT THEME LOADING\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement \nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment, this comment can span multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with an optional hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an array of values\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext {\n    content: \"Line one\\n\\tIndented line two\";\n}\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\` and `\"`.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the text.\n * `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n * `uppercase`: Uppercase the text.\n * `lowercase`: Lowercase the text.\n\n The following option is disabled as pango crashes on this if there is eel\n upsizing or wrapping. This will be re-enabled once fixed:\n\n * `capitalize`: Capitalize the text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n* `+`     : Add\n* `-`     : Subtract\n* `/`     : Divide\n* `*`     : Multiply\n* `%`     : Modulo\n* `min`   : Minimum of lvalue or rvalue;\n* `max`   : Maximum of lvalue or rvalue;\n* `floor` : Round down lvalue to the next multiple of rvalue \n* `ceil`  : Round up lvalue to the next multiple of rvalue \n* `round` : Round lvalue to the next multiple of rvalue \n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n\n## Position\n\nIndicate a place on the window/monitor.\n\n```\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n## Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n* Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the property\n`width` is not set, the default value is used.\n\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## List of values\n\n* Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n* Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\nIf the environment value is not found, the default value is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default value (`40%`).\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n      * `textbox-current-entry`: Shows the text of the currently selected entry.\n      * `icon-current-entry`: Shows the icon of the currently selected entry.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:           enable/disable rendering of the widget\n* **padding**:           padding\n  Padding on the inside of the widget\n* **margin**:            padding\n  Margin on the outside of the widget\n* **border**:            border\n  Border around the widget (between padding and margin)/\n* **border-radius**:     padding\n  Sets a radius on the corners of the borders.\n* **background-color**:  color\n  Background color\n* **background-image**:  image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:            cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:       distance\n* **y-offset**:       distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:          distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**/**content**:   the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **text-transform**:    text style {color} for the whole text.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n* **tab-stops**:         array of distances\n    Set the location of tab stops by their distance from the beginning of the line.\n    Each distance should be greater than the previous one.\n    The text appears to the right of the tab stop position (other alignments are not supported yet).\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **flow**:           orientation\n    The order the elements are layed out.  Vertical is the original 'column' view.\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n* **require-input**:    boolean\n    Listview requires user input to show up.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n * `enabled`:           Boolean option to enable. Supports environment variable.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```\n@media ( enabled: env(DO_LIGHT, false ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Icon Handling \n\nRofi supports 3 ways of specifying an icon:\n\n* Filename\n* icon-name, this is looked up via the icon-theme.\n* Markup String. It renders a string as an icon.\n\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.4/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA very useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme hicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your configuration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n\tdpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modes \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n`-refilter-timeout-limit`\n\nThe limit of elements that is used to switch from instant to delayed filter mode.\n\n  Default: 8192\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modes` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode \n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\n\n### Combi settings\n\n`-combi-modes ` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n* **mode**: the mode display name\n* **text**: the entry text\n\nPango markup can be used to formatting the output.\n\n    Default: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue tracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them up.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the `-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n* Window: It first uses the icon that the application exposes via the X11\n  Server, if none is set it does a lookup of the window Class name in the icon theme.\n* drun: It uses the icon set in the desktop file.\n* run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modes run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modes run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modes combi -show combi -combi-modes run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modes combi,window -show combi -combi-modes run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage. \n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi-debugging.5.markdown",
    "content": "# ROFI DEBUGGING 5 rofi debugging\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some small test\nto help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock* mode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact version, monitor layout\nand more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\n\nIt will show a trace with (useful) timing information at relevant points during the execution.\nThis will help debugging when rofi is slow to start.\n\nExample trace:\n\n```\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug information. This debug output can be enabled for\nmultiple parts in rofi using the glib debug framework. Debug domains can be enabled by setting the G\\_MESSAGES\\_DEBUG\nenvironment variable. At the time of creation of this page, the following debug domains exist:\n\n * all: Show debug information from all domains.\n * X11Helper: The X11 Helper functions.\n * View: The main window view functions.\n * Widgets.Box: The Box widget.\n * Modes.DMenu: The dmenu mode.\n * Modes.Run: The run mode.\n * Modes.DRun: The desktop file run mode.\n * Modes.Window: The window mode.\n * Modes.Script: The script mode.\n * Modes.Combi: The script mode.\n * Modes.Ssh: The ssh mode.\n * Rofi: The main application.\n * Timings: Get timing output.\n * Theme: Theme engine debug output. (warning lots of output).\n * Widgets.Icon: The Icon widget.\n * Widgets.Box: The box widget.\n * Widgets.Container: The container widget.\n * Widgets.Window: The window widget.\n * Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output from the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n\n## Creating a backtrace.\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it grabs keyboard and\nmouse. So if it crashes in GDB you are stuck.\nThe best way to go is to enable core file. (ulimit -c unlimited in bash) then make rofi crash. You\ncan then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a backtrace via `coredumpctl`.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi-dmenu.5.markdown",
    "content": "# ROFI-DMENU 5 rofi-dmenu\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too many flavors of `dmenu`.\nThe idea is that the basic usage command-line flags are obeyed, theme-related flags are not.\nBesides, **rofi** offers some extended features (like multi-select, highlighting, message bar, extra key bindings).\n\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into separate entries and displays them.\nIf the user selects a row, this is printed out to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the output a one application into \n**rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation mode.\n\n```bash\nls | rofi -dmenu\n```\n\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or symlink **rofi** to dmenu in `$PATH`.\n\n    ln -s /usr/bin/rofi /usr/bin/dmenu\n\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the **rofi-script(5)** manpage for more information.\n\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input. See the **rofi-script(5)** manpage\nfor more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a separator:\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey', a,b,c,d, or e.\n\n    echo \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n    rofi -dmenu -l 25\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of python(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the last row with -2 preceding it, ranges are left-open and right-close, and so on. You can specify:\n\n  * A single row: '5'\n  * A range of (last 3) rows: '-3:'\n  * 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n  * A set of rows: '2,0,-9'\n  * Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input entries):\n\n  * 's' selected string\n  * 'i' index (0 - (N-1))\n  * 'd' index (1 - N)\n  * 'q' quote string\n  * 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n  * 'f' filter string (user input)\n  * 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup.\nFor more information on supported markup, see [here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html) for details about Pango markup.\n\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the left of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the selection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used with conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n## RETURN VALUE\n\n * **0**: Row has been selected accepted by user.\n * **1**: User cancelled the selection.\n * **10-28**: Row accepted by custom keybinding.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5), rofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi-keys.5.markdown",
    "content": "# ROFI-KEYS 5 rofi-keys\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings \n\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n\n## Keyboard Bindings\n\n### **kb-primary-paste**:\nPaste primary selection\n\n  **Default**: \tControl+V,Shift+Insert \n\n### **kb-secondary-paste**\nPaste clipboard\n\n**Default**: \tControl+v,Insert \n\n### **kb-clear-line**\nClear input line\n\n**Default**: \tControl+w \n\n### **kb-move-front**\nBeginning of line\n\n**Default**: \tControl+a \n\n### **kb-move-end**\nEnd of line\n\n**Default**: \tControl+e \n\n### **kb-move-word-back**\nMove back one word\n\n**Default**: \tAlt+b,Control+Left \n\n### **kb-move-word-forward**\nMove forward one word\n\n**Default**: \tAlt+f,Control+Right \n\n### **kb-move-char-back**\nMove back one char\n\n**Default**: \tLeft,Control+b \n\n### **kb-move-char-forward**\nMove forward one char\n\n**Default**: \tRight,Control+f \n\n### **kb-remove-word-back**\nDelete previous word\n\n**Default**: \tControl+Alt+h,Control+BackSpace \n\n### **kb-remove-word-forward**\nDelete next word\n\n**Default**: \tControl+Alt+d \n\n### **kb-remove-char-forward**\nDelete next char\n\n**Default**: \tDelete,Control+d \n\n### **kb-remove-char-back**\nDelete previous char\n\n**Default**: \tBackSpace,Shift+BackSpace,Control+h \n\n### **kb-remove-to-eol**\nDelete till the end of line\n\n**Default**: \tControl+k \n\n### **kb-remove-to-sol**\nDelete till the start of line\n\n**Default**: \tControl+u \n\n### **kb-accept-entry**\nAccept entry\n\n**Default**: \tControl+j,Control+m,Return,KP_Enter \n\n### **kb-accept-custom**\nUse entered text as command (in ssh/run modes)\n\n**Default**: \tControl+Return \n\n### **kb-accept-custom-alt**\nUse entered text as command (in ssh/run modes)\n\n**Default**: \tControl+Shift+Return \n\n### **kb-accept-alt**\nUse alternate accept command.\n\n**Default**: \tShift+Return \n\n### **kb-delete-entry**\nDelete entry from history\n\n**Default**: \tShift+Delete \n\n### **kb-mode-next**\nSwitch to the next mode.\n\n**Default**: \tShift+Right,Control+Tab \n\n### **kb-mode-previous**\nSwitch to the previous mode.\n\n**Default**: \tShift+Left,Control+ISO_Left_Tab \n\n### **kb-mode-complete**\nStart completion for mode.\n\n**Default**: \tControl+l \n\n### **kb-row-left**\nGo to the previous column\n\n**Default**: \tControl+Page_Up \n\n### **kb-row-right**\nGo to the next column\n\n**Default**: \tControl+Page_Down \n\n### **kb-row-up**\nSelect previous entry\n\n**Default**: \tUp,Control+p \n\n### **kb-row-down**\nSelect next entry\n\n**Default**: \tDown,Control+n \n\n### **kb-row-tab**\nGo to next row, if one left, accept it, if no left next mode.\n\n**Default**: \t\n\n### **kb-element-next**\nGo to next row.\n\n**Default**: Tab\t\n\n### **kb-element-prev**\nGo to previous row.\n\n**Default**: ISO_Left_Tab\n\n### **kb-page-prev**\nGo to the previous page\n\n**Default**: \tPage_Up \n\n### **kb-page-next**\nGo to the next page\n\n**Default**: \tPage_Down \n\n### **kb-row-first**\nGo to the first entry\n\n**Default**: \tHome,KP_Home \n\n### **kb-row-last**\nGo to the last entry\n\n**Default**: \tEnd,KP_End \n\n### **kb-row-select**\nSet selected item as input text\n\n**Default**: \tControl+space \n\n### **kb-screenshot**\nTake a screenshot of the rofi window\n\n**Default**: \tAlt+S \n\n### **kb-ellipsize**\nToggle between ellipsize modes for displayed data\n\n**Default**: \tAlt+period \n\n### **kb-toggle-case-sensitivity**\nToggle case sensitivity\n\n**Default**: \tgrave,dead_grave \n\n### **kb-toggle-sort**\nToggle sort\n\n**Default**: \tAlt+grave \n\n### **kb-cancel**\nQuit rofi\n\n**Default**: \tEscape,Control+g,Control+bracketleft \n\n### **kb-custom-1**\nCustom keybinding 1\n\n**Default**: \tAlt+1 \n\n### **kb-custom-2**\nCustom keybinding 2\n\n**Default**: \tAlt+2 \n\n### **kb-custom-3**\nCustom keybinding 3\n\n**Default**: \tAlt+3 \n\n### **kb-custom-4**\nCustom keybinding 4\n\n**Default**: \tAlt+4 \n\n### **kb-custom-5**\nCustom Keybinding 5\n\n**Default**: \tAlt+5 \n\n### **kb-custom-6**\nCustom keybinding 6\n\n**Default**: \tAlt+6 \n\n### **kb-custom-7**\nCustom Keybinding 7\n\n**Default**: \tAlt+7 \n\n### **kb-custom-8**\nCustom keybinding 8\n\n**Default**: \tAlt+8 \n\n### **kb-custom-9**\nCustom keybinding 9\n\n**Default**: \tAlt+9 \n\n### **kb-custom-10**\nCustom keybinding 10\n\n**Default**: \tAlt+0 \n\n### **kb-custom-11**\nCustom keybinding 11\n\n**Default**: \tAlt+exclam \n\n### **kb-custom-12**\nCustom keybinding 12\n\n**Default**: \tAlt+at \n\n### **kb-custom-13**\nCustom keybinding 13\n\n**Default**: \tAlt+numbersign \n\n### **kb-custom-14**\nCustom keybinding 14\n\n**Default**: \tAlt+dollar \n\n### **kb-custom-15**\nCustom keybinding 15\n\n**Default**: \tAlt+percent \n\n### **kb-custom-16**\nCustom keybinding 16\n\n**Default**: \tAlt+dead_circumflex \n\n### **kb-custom-17**\nCustom keybinding 17\n\n**Default**: \tAlt+ampersand \n\n### **kb-custom-18**\nCustom keybinding 18\n\n**Default**: \tAlt+asterisk \n\n### **kb-custom-19**\nCustom Keybinding 19\n\n**Default**: \tAlt+parenleft \n\n### **kb-select-1**\nSelect row 1\n\n**Default**: \tSuper+1 \n\n### **kb-select-2**\nSelect row 2\n\n**Default**: \tSuper+2 \n\n### **kb-select-3**\nSelect row 3\n\n**Default**: \tSuper+3 \n\n### **kb-select-4**\nSelect row 4\n\n**Default**: \tSuper+4 \n\n### **kb-select-5**\nSelect row 5\n\n**Default**: \tSuper+5 \n\n### **kb-select-6**\nSelect row 6\n\n**Default**: \tSuper+6 \n\n### **kb-select-7**\nSelect row 7\n\n**Default**: \tSuper+7 \n\n### **kb-select-8**\nSelect row 8\n\n**Default**: \tSuper+8 \n\n### **kb-select-9**\nSelect row 9\n\n**Default**: \tSuper+9 \n\n### **kb-select-10**\nSelect row 10\n\n**Default**: \tSuper+0 \n\n## Mouse Bindings\n\n### **ml-row-left**\nGo to the previous column\n\n**Default**: \tScrollLeft \n\n### **ml-row-right**\nGo to the next column\n\n**Default**: \tScrollRight \n\n### **ml-row-up**\nSelect previous entry\n\n**Default**: \tScrollUp \n\n### **ml-row-down**\nSelect next entry\n\n**Default**: \tScrollDown \n\n### **me-select-entry**\nSelect hovered row\n\n **Default**: \tMousePrimary \n\n### **me-accept-entry**\nAccept hovered row\n\n**Default**: \tMouseDPrimary \n\n### **me-accept-custom**\nAccept hovered row with custom action\n\n**Default**: \tControl+MouseDPrimary \n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5) \n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi-script.5.markdown",
    "content": "# ROFI-SCRIPT 5 rofi-script\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax: \"{name}:{executable}\"\n\nFor example:\n\n```\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi closes.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the 'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script.\nExtra options are lines that start with a NULL character (`\\0`) followed by a key, separator (`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n * **prompt**:      Update the prompt text.\n * **message**:     Update the message text.\n * **markup-rows**: If 'true' renders markup in the row.\n * **urgent**:      Mark rows as urgent. (for syntax see the urgent option in dmenu mode)\n * **active**:      Mark rows as active. (for syntax see the active option in dmenu mode)\n * **delim**:       Set the delimiter for for next rows. Default is '\\n' and this option should finish with this. Only call this on first call of script, it is remembered for consecutive calls.\n * **no-custom**:   If set to 'true'; only accept listed entries, ignore custom input.\n * **use-hot-keys**: If set to true, it enabled the Custom keybindings for script. Warning this breaks the normal rofi flow.\n * **keep-selection**: If set, the selection is not moved to the first entry, but the current position is maintained. The filter is cleared.\n * **new-selection**: If `keep-selection` is set, this allows you to override the selected entry (absolute position). \n * **data**:         Passed data to the next execution of the script via **ROFI_DATA**.\n * **theme**:       Small theme snippet to f.e. change the background color of a widget.\n\n## Parsing row options\n\nExtra options for individual rows can be set.\nThe extra option can be specified following the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n * **icon**: Set the icon for that row.\n * **meta**: Specify invisible search terms.\n * **nonselectable**: If true the row cannot activated.\n * **info**: Info that, on selection, gets placed in the `ROFI_INFO` environment variable. This entry does not get searched.\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make sure it is launched in the background.\nIf not rofi will wait for its output (to display).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash handles escaped values for the separators.\nSee issue #1201 on github.\n\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi-theme.5.markdown",
    "content": "# ROFI-THEME 5 rofi-theme\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## GETTING STARTED WITH THEMING \n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the  \nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`.\nTo find the commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text` widget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## DEFAULT THEME LOADING\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement \nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## DESCRIPTION\n\nThe need for a new theme format was motivated by the fact that the way rofi handled widgets has changed. From a very\nstatic drawing of lines and text to a nice structured form of packing widgets. This change made it possible to provide a\nmore flexible theme framework. The old theme format and config file are not flexible enough to expose these options in a\nuser-friendly way. Therefore, a new file format has been created, replacing the old one.\n\n## FORMAT SPECIFICATION\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`) newlines format are supported. But unix is\npreferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n* Anything after  `// ` and before a newline is considered a comment.\n* Everything between `/*` and `*/` is a comment, this comment can span multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be defined in section `* { }`.\nSub-section names begin with an optional hash symbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate properties are overwritten and the last\nparsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than one,\nthey will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n * a string\n * an integer number\n * a fractional number\n * a boolean value\n * a color\n * image\n * text style\n * line style\n * a distance\n * a padding\n * a border\n * a position\n * a reference\n * an orientation\n * a cursor\n * a list of keywords\n * an array of values\n * an environment variable\n * Inherit\n\nSome of these types are a combination of other types.\n\n## String\n\n* Format:  `\"[:print:]+\"`\n\nA string is always surrounded by double quotes (`\"`). Between the quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext {\n    content: \"Line one\\n\\tIndented line two\";\n}\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\` and `\"`.\n\n## Integer\n\n* Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n## Real\n\n* Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n## Boolean\n\n* Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n## Image\n\n**rofi** support a limited set of background-image formats.\n\n* Format: url(\"path to image\");\n* Format: url(\"path to image\", scale);\n  where scale is: none, both, width, height\n* Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n* Format: linear-gradient(to direction, stop color,stop1, color, stop2 color, ...);\n  where direction is:   top,left,right,bottom.\n* Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n  Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n## Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and some of CSS 4)\n\n* Format: `#{HEX}{3}` (rgb)\n* Format: `#{HEX}{4}` (rgba)\n* Format: `#{HEX}{6}` (rrggbb)\n* Format: `#{HEX}{8}` (rrggbbaa)\n* Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n* Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n* Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n* Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE} ])`\n* Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n * `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n * `{INTEGER}` value can be between 0 and 255 or 0-100 when representing percentage.\n * `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad` or `turn`. When no unit is specified, degrees is assumed.\n * `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n * `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown,\n    BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan,\n    DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed,\n    DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue,\n    DimGray, DimGrey, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen,\n    LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink,\n    LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen,\n    Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy,\n    OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed,\n    PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen,\n    SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen,transparent\n\n\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n## Text style\n\n* Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates that no emphasis\nshould be applied.\n\n * `bold`: make the text thicker then the surrounding text.\n * `italic`: put the highlighted text in script type (slanted).\n * `underline`: put a line under the text.\n * `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n * `uppercase`: Uppercase the text.\n * `lowercase`: Lowercase the text.\n\n The following option is disabled as pango crashes on this if there is eel\n upsizing or wrapping. This will be re-enabled once fixed:\n\n * `capitalize`: Capitalize the text.\n\n## Line style\n\n* Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n * `dash`:  a dashed line, where the gap is the same width as the dash\n * `solid`: a solid line\n\n## Distance\n\n* Format: `{Integer}px`\n* Format: `{Real}em`\n* Format: `{Real}ch`\n* Format: `{Real}%`\n* Format: `{Integer}mm`\n\nA distance can be specified in 3 different units:\n\n* `px`: Screen pixels.\n* `em`: Relative to text height.\n* `ch`: Relative to width of a single number.\n* `mm`: Actual size in millimeters (based on dpi).\n* `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n* `+`     : Add\n* `-`     : Subtract\n* `/`     : Divide\n* `*`     : Multiply\n* `%`     : Modulo\n* `min`   : Minimum of lvalue or rvalue;\n* `max`   : Maximum of lvalue or rvalue;\n* `floor` : Round down lvalue to the next multiple of rvalue \n* `ceil`  : Round up lvalue to the next multiple of rvalue \n* `round` : Round lvalue to the next multiple of rvalue \n\nIt uses the C precedence ordering.\n\n## Padding\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n* 1 field: `all`\n* 2 fields: `top&bottom` `left&right`\n* 3 fields: `top`, `left&right`, `bottom`\n* 4 fields: `top`, `right`, `bottom`, `left`\n\n\n## Border\n\n* Format: `{Integer}`\n* Format: `{Distance}`\n* Format: `{Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance}`\n* Format: `{Distance} {Distance} {Distance} {Distance}`\n* Format: `{Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n* Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n\n## Position\n\nIndicate a place on the window/monitor.\n\n```\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n* Format: `(center|east|north|west|south|north east|north west|south west|south east)`\n\n## Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n\n## Reference\n\n* Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\nFor example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n* Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of redirects is 20.\nA property always refers to another property. It cannot be used for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the property\n`width` is not set, the default value is used.\n\n\n## Orientation\n\n * Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n## Cursor\n\n * Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the widget.\n\n## List of keywords\n\n* Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\nThe `keyword` in the list refers to an widget name.\n\n## List of values\n\n* Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are comma-separated.\n\n## Environment variable\n\n* Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n* Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can be any of the above types).\nThe environment variable should be an alphanumeric string without white-space.\nIf the environment value is not found, the default value is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default value (`40%`).\n\n## Inherit\n\n * Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n\n## ELEMENTS PATHS\n\nElement paths exists of two parts, the first part refers to the actual widget by name.\nSome widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of the widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the same:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n## SUPPORTED ELEMENT PATH\n\n## Name\n\nThe current widgets available in **rofi**:\n\n* `window`\n  * `overlay`: the overlay widget.\n  * `mainbox`: The mainbox box.\n    * `inputbar`: The input bar box.\n      * `box`: the horizontal @box packing the widgets\n      * `case-indicator`: the case/sort indicator @textbox\n      * `prompt`: the prompt @textbox\n      * `entry`: the main entry @textbox\n      * `num-rows`: Shows the total number of rows.\n      * `num-filtered-rows`: Shows the total number of rows after filtering.\n      * `textbox-current-entry`: Shows the text of the currently selected entry.\n      * `icon-current-entry`: Shows the icon of the currently selected entry.\n    * `listview`: The listview.\n       * `scrollbar`: the listview scrollbar\n       * `element`: a box in the listview holding the entries\n           * `element-icon`: the widget in the listview's entry showing the (optional) icon\n           * `element-index`: the widget in the listview's entry keybindable index (1,2,3..0)\n           * `element-text`: the widget in the listview's entry showing the text.\n    * `mode-switcher`: the main horizontal @box packing the buttons.\n      * `button`: the buttons @textbox for each mode\n    * `message`: The container holding the textbox.\n      * `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a custom layout will have different\nelements, and structure.\n\n\n## State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n### Example:\n\n`button selected.normal { }`\n\n`element selected.urgent { }`\n\nCurrently only the entrybox and scrollbar have states:\n\n### Entrybox:\n\n`{visible modifier}.{state}`\n\nWhere `visible modifier` can be:\n * normal: no modification\n * selected: the entry is selected/highlighted by user\n * alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n * normal: no modification\n * urgent: this entry is marked urgent\n * active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background color.\nNote that a state modifies the original element, it therefore contains all the properties of that element.\n\n### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n\n## SUPPORTED PROPERTIES\n\nThe following properties are currently supported:\n\n###  all widgets:\n\n* **enabled**:           enable/disable rendering of the widget\n* **padding**:           padding\n  Padding on the inside of the widget\n* **margin**:            padding\n  Margin on the outside of the widget\n* **border**:            border\n  Border around the widget (between padding and margin)/\n* **border-radius**:     padding\n  Sets a radius on the corners of the borders.\n* **background-color**:  color\n  Background color\n* **background-image**:  image\n  Background image\n* **border-color**:      color\n  Color of the border\n* **cursor**:            cursor\n  Type of mouse cursor that is set when the mouse pointer is hovered over the widget.\n\n### window:\n\n* **font**:            string\n  The font used in the window\n\n* **transparency**:    string\n  Indicating if transparency should be used and what type:\n  **real** - True transparency. Only works with a compositor.\n  **background** - Take a screenshot of the background image and use that.\n  **screenshot** - Take a screenshot of the screen and use that.\n  **Path** to png file - Use an image.\n\n* **location**:       position\n    The place of the anchor on the monitor\n* **anchor**:         anchor\n    The anchor position on the window\n* **fullscreen**:     boolean\n    Window is fullscreen.\n* **width**:          distance\n    The width of the window\n* **x-offset**:       distance\n* **y-offset**:       distance\n    The offset of the window to the anchor point, allowing you to push the window left/right/up/down\n\n\n### scrollbar:\n\n* **background-color**:    color\n* **handle-width**:        distance\n* **handle-color**:        color\n* **border-color**:        color\n\n### box:\n\n* **orientation**:      orientation\n        Set the direction the elements are packed.\n* **spacing**:          distance\n        Distance between the packed elements.\n\n### textbox:\n\n* **background-color**:  color\n* **border-color**:      the color used for the border around the widget.\n* **font**:              the font used by this textbox (string).\n* **str**/**content**:   the string to display by this textbox (string).\n* **vertical-align**:    Vertical alignment of the text. A number between 0 (top) and 1 (bottom).\n* **horizontal-align**:  Horizontal alignment of the text. A number between 0 (left) and 1 (right).\n* **text-color**:        the text color to use.\n* **text-transform**:    text style {color} for the whole text.\n* **highlight**:         text style {color}.\n    color is optional, multiple highlight styles can be added like: bold underline italic #000000;\n    This option is only available on the `element-text` widget.\n* **width**:             override the desired width for the textbox.\n* **content**:           Set the displayed text (String).\n* **placeholder**:       Set the displayed text (String) when nothing is entered.\n* **placeholder-color**: Color of the placeholder text.\n* **blink**:             Enable/Disable blinking on an input textbox (Boolean).\n* **markup**:            Force markup on, beware that only valid pango markup strings are shown.\n* **tab-stops**:         array of distances\n    Set the location of tab stops by their distance from the beginning of the line.\n    Each distance should be greater than the previous one.\n    The text appears to the right of the tab stop position (other alignments are not supported yet).\n\n### listview:\n* **columns**:         integer\n    Number of columns to show (at least 1)\n* **fixed-height**:    boolean\n    Always show `lines` rows, even if fewer elements are available.\n* **dynamic**:         boolean\n    `True` if the size should change when filtering the list, `False` if it should keep the original height.\n* **scrollbar**:       boolean\n    If the scrollbar should be enabled/disabled.\n* **scrollbar-width**: distance\n    Width of the scrollbar\n* **cycle**:           boolean\n    When navigating, it should wrap around\n* **spacing**:         distance\n    Spacing between the elements (both vertical and horizontal)\n* **lines**:           integer\n    Number of rows to show in the list view.\n* **layout**:           orientation\n    Indicate how elements are stacked. Horizontal implements the dmenu style.\n* **reverse**:         boolean\n    Reverse the ordering (top down to bottom up).\n* **flow**:           orientation\n    The order the elements are layed out.  Vertical is the original 'column' view.\n* **fixed-columns**:    boolean\n    Do not reduce the number of columns shown when number of visible elements is not enough to fill them all.\n* **require-input**:    boolean\n    Listview requires user input to show up.\n\nEach element is a `box` called `element`. Each `element` can contain an `element-icon` and `element-text`.\n\n### listview text highlight:\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used) to change\nthe style of highlighting.\nThe `highlight` property consist of the `text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked extensively.\nFor each widget, the themer can specify padding, margin, border, font, and more.\nIt even allows, as an advanced feature, to pack widgets in a custom structure.\n\n### Basic structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n> * ci is the case-indicator\n> * fr is the num-filtered-rows\n> * ns is the num-rows\n\n### Error message structure\n\n```\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a custom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n * prompt\n * entry\n * overlay\n * case-indicator\n * message\n * listview\n * mode-switcher\n * num-rows\n * num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a subset of the widgets.\nThese are used in the default theme as depicted in the figure above.\n\n * mainbox\n   Packs: `inputbar, message, listview, mode-switcher`\n * inputbar\n   Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box widgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the widget:\n\n#### textbox\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size with `size`.\nIf the property `action` is set, it acts as a button.\n`action` can be set to a keybinding name and completes that action. (see rofi -show keys for a list).\n\nIf the `squared` property is set to **false** the widget height and width are not forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action.\nThe `action` can be set to:\n`keybinding`: accepts a keybinding name and completes that action. (see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n * Content - The content of the widget.\n * Padding - Clears an area around the widget.\n   The padding shows the background color of the widget.\n * Border - A border that goes around the padding and content.\n   The border use the border-color of the widget.\n * Margin - Clears an area outside the border.\n   The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space between elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview) have the `spacing` property.\nThis property sets the distance between the packed widgets (both horizontally and vertically).\n\n```\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to make one widget centered:\n\n```\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on the `expand` flag of child the\nremaining space will be equally divided between both dummy and child widget (expand enabled), or both dummy widgets\n(expand disabled).\n\n## DEBUGGING\n\nTo get debug information from the parser, run rofi like:\n\n```\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the above command.\n\nTo see the elements queried during running, run:\n\n```\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for example to set it to full-screen:\n\n```\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n * `min-width`:         load when width is bigger or equal then value.\n * `max-width`:         load when width is smaller then value.\n * `min-height`:        load when height is bigger or equal then value.\n * `max-height`:        load when height is smaller then value.\n * `min-aspect-ratio`   load when aspect ratio is over value.\n * `max-aspect-ratio`:  load when aspect ratio is under value.\n * `monitor-id`:        The monitor id, see rofi -help for id's.\n * `enabled`:           Boolean option to enable. Supports environment variable.\n\n@media takes an integer number or a fraction, for integer number `px` can be added.\n\n\n```\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```\n@media ( enabled: env(DO_LIGHT, false ) {\n\n}\n```\n\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should be specified in a format that pango\nunderstands.\nThis normally is the font name followed by the font size. For example:\n\n```\nmono 18\n```\n\nOr\n\n```\nFontAwesome 22\n```\n\n## Icon Handling \n\nRofi supports 3 ways of specifying an icon:\n\n* Filename\n* icon-name, this is looked up via the icon-theme.\n* Markup String. It renders a string as an icon.\n\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files.\nThis can be used to modify existing themes, or have multiple variations on a theme.\n\n * import:  Import and parse a second file.\n * theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n * `${XDG_CONFIG_HOME}/rofi/themes/`\n * `${XDG_CONFIG_HOME}/rofi/`\n * `${XDG_DATA_HOME}/rofi/themes/`\n * `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved as a filename by appending the `.rasi` extension.\n\n\n\n## EXAMPLES\n\nSeveral examples are installed together with **rofi**. These can be found in `{datadir}/rofi/themes/`, where\n`{datadir}` is the install path of **rofi** data. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.5/rofi.1.markdown",
    "content": "# ROFI 1 rofi\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu replacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show <mode>`.\nTo show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA very useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n    rofi -e \"my message\"\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated in order below):\n\n * System configuration file  (for example `/etc/rofi.rasi`).\n   It first checks `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n   It loads the first config file it finds, it does not merge multiple system configuration files.\n * Rasi theme file: The new *theme* format can be used to set configuration values.\n * Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified options are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme hicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your configuration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n\tdpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n * string\n * integer (signed and unsigned)\n * char\n * boolean\n * lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n    -X\n\nTo disable option X:\n\n    -no-X\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n  * 0: Autodetect the number of supported hardware threads.\n  * 1: Disable threading\n  * 2..n: Specify the maximum number of threads to use in the thread pool.\n\n    Default:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n\nOr get the options from a script:\n\n    ~/my_script.sh | rofi -dmenu\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n    rofi -show run\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n    rofi -modes \"run,ssh\" -show run\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n    <name>:<script>\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh` script:\n\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n\n`-case-sensitive`\n\nStart in case-sensitive mode.\nThis option can be changed at run-time using the `-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches `e`.  \nThis is not a perfect implementation, but works. For now, it disables highlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used.\nIf not specified default theme from DE is used, *Adwaita* and *gnome* themes act as\nfallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like Clerk that are basically an application.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when launched.\n\n`-refilter-timeout-limit`\n\nThe limit of elements that is used to switch from instant to delayed filter mode.\n\n  Default: 8192\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n* **normal**: match the int string\n* **regex**: match a regex input\n* **glob**: match a glob pattern\n* **fuzzy**: do a fuzzy match\n* **prefix**: match prefix\n\n   Default: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all the above\n\n    Default: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's  executable\n* **categories**: the application's categories\n* **comment**: the application comment\n\nPango markup can be used to formatting the output.\n\n    Default: {name} [<span weight='light' size='small'><i>({generic})</i></span>]\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format string.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\n    Default: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all the above\n\n    Default: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the next keyword).\nSet to '\\x0' to disable.\n\n    Default: '-'\n\n\n### Layout and Theming\n\n**IMPORTANT:**\n  In newer **rofi** releases, all the theming options have been moved into the new theme format. They are no longer normal\n  **rofi** options that can be passed directly on the command line (there are too many).\n  Small snippets can be passed on the command line: `rofi -theme-str 'window {width: 50%;}'` to override a single\n  setting. They are merged into the current theme.\n  They can also be appended at the end of the **rofi** config file to override parts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please use the new theme format to customize\n**rofi**. More information about the new format can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following locations on screen:\n\n      1 2 3\n      8 0 4\n      7 6 5\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the bottom.\n(See `-modes` option)\nTo show sidebar, use:\n\n    rofi -show run -sidebar-mode \n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best combined with custom mouse bindings.\nTo utilize hover-select and accept an entry in a single click, use:\n\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*\n\n`-m` *name*\n\n`-monitor` *num*\n\n`-monitor` *name*\n\nSelect monitor to display **rofi** on.\nIt accepts as input: *primary* (if primary output is set), the *xrandr* output name, or integer number (in order of\ndetection). Negative numbers are handled differently:\n\n *  **-1**: the currently focused monitor.\n *  **-2**: the currently focused window (that is, **rofi** will be displayed on top of the focused window).\n *  **-3**: Position of mouse (overrides the location setting to get normal context menu\n    behavior.)\n *  **-4**: the monitor with the focused window.\n *  **-5**: the monitor that shows the mouse pointer.\n\n    Default: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n    rofi -theme-str '#window { fullscreen: true; }'\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n* If set to `0`, it tries to auto-detect based on X11 screen size (similar to i3 and GTK).\n* If set to `1`, it tries to auto-detect based on the size of the monitor that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n    rofi -terminal xterm\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-parse-known-hosts`\n`-no-parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses `run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n * **w**: desktop name\n * **t**: title of window\n * **n**: name\n * **r**: role\n * **c**: class\n\n*len*: maximum field length (0 for auto-size). If length and window *width* are negative, field length is *width - len*.  \nIf length is positive, the entry will be truncated or padded to fill that length.\n\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be closed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\n\n### Combi settings\n\n`-combi-modes ` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying an exec command.\nFor that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n* **mode**: the mode display name\n* **text**: the entry text\n\nPango markup can be used to formatting the output.\n\n    Default: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n\n### History and Sorting\n\n`-disable-history`\n`-no-disable-history` (re-enable history)\n\nDisable history\n\n`-sort` to enable\n`-no-sort` to disable\n\nEnable, disable sorting.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sorting method.\n\nThere are 2 sorting methods:\n\n * levenshtein (Default)\n * fzf sorting.\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can cause slowdowns when set too high)\n\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems with slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of desktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file prevents multiple **rofi** instances from running simultaneously. This is useful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n\n`-click-to-exit`\n`-no-click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue tracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can enter the used command-line. The following keys can be used that will be replaced at runtime:\n\n  * `{host}`: the host to connect to\n  * `{terminal}`: the configured terminal (see -terminal)\n  * `{ssh-client}`: the configured ssh client (see -ssh-client)\n  * `{cmd}`: the command to execute\n  * `{window}`: the window ID of the selected window (in `window-command`)\n\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them up.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will close the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between them.\nPressing the `delete-entry` binding (`shift-delete`) will kill the window.\nPressing the `accept-custom` binding (`control-enter` or `shift-enter`) will run a command on the window.\n(See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a terminal).\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\nwith a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed desktop files. It automatically launches them\nin a terminal if specified in the Desktop File.\nPressing the `delete-entry` binding (`shift-delete`) will remove this entry from the run history.\nPressing the `accept-custom` binding (`control-enter`) will run the command as entered in the entry box.\nPressing the `accept-alt` binding (`shift-enter`) will run the command in a terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File Browser mode to launch the application\npassing a file as argument if specified in the desktop file.\n\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/) and should be compatible with\napplications using this standard.  Some applications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why desktop files are\ndiscarded.\n\nThere are two advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to quickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage for more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the `-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned.\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black.\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\") instead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n    ` ` Case insensitive and no sorting.\n    `-` Case sensitivity enabled, no sorting.\n    `+` Case insensitive and Sorting enabled\n    `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n* Window: It first uses the icon that the application exposes via the X11\n  Server, if none is set it does a lookup of the window Class name in the icon theme.\n* drun: It uses the icon set in the desktop file.\n* run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n    rofi -modes run -show run\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n    rofi -modes run,drun -show run\n\nCombine the run and Desktop File run dialog (`drun`):\n\n    rofi -modes combi -show combi -combi-modes run,drun\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to window switcher:\n\n    rofi -modes combi,window -show combi -combi-modes run,drun\n\nPop up a text message claiming that this is the end:\n\n    rofi -e \"This is the end\"\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n\nShow all key bindings:\n\n    rofi -show keys\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key release. Otherwise, it cannot grab the keyboard.\nSee also the i3 [manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a KeyPress event, because the keyboard/pointer is\nstill grabbed. For these situations, the `--release` flag can be used, as it will execute the command after the keys have\nbeen released.\n\n## LICENSE\n\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n * [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n * [Forum (Reddit)](https://reddit.com/r/qtools//)\n * [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage. \n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**, **rofi-theme(5)**, **rofi-script(5)**, **rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n* Rasmus Steinke <rasi@xssn.at>\n* Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared. \n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-sensible-terminal.1.markdown",
    "content": "# rofi-sensible-terminal(1)\n\n## NAME\n\n**rofi-sensible-terminal** -  launches $TERMINAL with fallbacks\n\n## SYNOPSIS\n\nrofi-sensible-terminal [arguments]\n\n## DESCRIPTION\n\nrofi-sensible-terminal is invoked in the rofi default config to start a terminal. This\nwrapper script is necessary since there is no distribution-independent terminal launcher\n(but for example Debian has x-terminal-emulator). Distribution packagers are responsible for\nshipping this script in a way which is appropriate for the distribution.\n\nIt tries to start one of the following (in that order):\n\n* `$TERMINAL` (this is a non-standard variable)\n* x-terminal-emulator\n* urxvt\n* rxvt\n* st\n* terminology\n* qterminal\n* Eterm\n* aterm\n* uxterm\n* xterm\n* roxterm\n* xfce4-terminal.wrapper\n* mate-terminal\n* lxterminal\n* konsole\n* alacritty\n* kitty\n* wezterm\n\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nDave Davenport and contributors\n\nCopied script from i3:\nMichael Stapelberg and contributors\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-theme-selector.1.markdown",
    "content": "# rofi-theme-selector(1)\n\n## NAME\n\n**rofi-theme-selector** - Preview and apply themes for **rofi**\n\n## DESCRIPTION\n\n**rofi-theme-selector** is a bash/rofi script to preview and apply themes for\n**rofi**. It's part of any installation of **rofi**.\n\n## USAGE\n\n### Running rofi-theme-selector\n\n**rofi-theme-selector** shows a list of all available themes in a **rofi**\nwindow. It lets you preview each theme with the Enter key and apply the theme\nto your **rofi** configuration file with Alt+a.\n\n## Theme directories\n\n**rofi-theme-selector** searches the following directories for themes:\n\n- ${PREFIX}/share/rofi/themes\n- $XDG_CONFIG_HOME/rofi/themes\n- $XDG_DATA_HOME/share/rofi/themes\n\n${PREFIX} reflects the install location of rofi. In most cases this will be\n\"/usr\".<br>\n$XDG_CONFIG_HOME is normally unset. Default path is \"$HOME/.config\".<br>\n$XDG_DATA_HOME is normally unset. Default path is \"$HOME/.local/share\".\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nQball Cow qball@gmpclient.org<br>\nRasmus Steinke rasi@xssn.at\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also specify the color and width of the cursor. You could, for example,\ncreate a crimson block cursor like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n-   Anything after  `// ` and before a newline is considered a comment.\n\n-   Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n-   Format: url(\"path to image\");\n\n-   Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n-   Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n-   Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n-   Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n-   Format: `#{HEX}{3}` (rgb)\n\n-   Format: `#{HEX}{4}` (rgba)\n\n-   Format: `#{HEX}{6}` (rrggbb)\n\n-   Format: `#{HEX}{8}` (rrggbbaa)\n\n-   Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n-   Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n-   Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n-   Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n-   Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n-   Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n-   `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n-   `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n-   `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n-   `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n-   `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue \n- `ceil`   : Round up lvalue to the next multiple of rvalue \n- `round`  : Round lvalue to the next multiple of rvalue \n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n-   Format: `{Integer}`\n\n-   Format: `{Distance}`\n\n-   Format: `{Distance} {Distance}`\n\n-   Format: `{Distance} {Distance} {Distance}`\n\n-   Format: `{Distance} {Distance} {Distance} {Distance}`\n\n-   Format: `{Distance} {Line style}`\n\n-   Format: `{Distance} {Line style} {Distance} {Line style}`\n\n-   Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n-   Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  -   `overlay`: the overlay widget.\n\n  -   `mainbox`: The mainbox box.\n\n   -   `inputbar`: The input bar box.\n       -   `box`: the horizontal @box packing the widgets\n\n          -   `case-indicator`: the case/sort indicator @textbox\n\n          -   `prompt`: the prompt @textbox\n\n          -   `entry`: the main entry @textbox\n\n          -   `num-rows`: Shows the total number of rows.\n\n          -   `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n          -   `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n          -   `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n   -   `listview`: The listview.\n\n       -   `scrollbar`: the listview scrollbar\n\n       -   `element`: a box in the listview holding the entries\n\n\t     -   `element-icon`: the widget in the listview's entry showing the\n\t\t (optional) icon\n\n\t     -   `element-index`: the widget in the listview's entry\n\t\t keybindable index (1,2,3..0)\n\n\t     -   `element-text`: the widget in the listview's entry showing the\n\t\t text.\n\n   -   `mode-switcher`: the main horizontal @box packing the buttons.\n       - `button`: the buttons @textbox for each mode\n\n   -   `message`: The container holding the textbox.\n       - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n###  all widgets\n\n-   **enabled**:           enable/disable rendering of the widget\n\n-   **padding**:           padding\n    Padding on the inside of the widget\n\n-   **margin**:            padding\n    Margin on the outside of the widget\n\n-   **border**:            border\n    Border around the widget (between padding and margin)/\n\n-   **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n\n-   **background-color**:  color\n    Background color\n\n-   **background-image**:  image\n    Background image\n\n-   **border-color**:      color\n    Color of the border\n\n-   **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n-   **font**:            string\n    The font used in the window\n\n-   **transparency**:    string\n    Indicating if transparency should be used and what type:\n    - **real** - True transparency. Only works with a compositor.\n    - **background** - Take a screenshot of the background image and use that.\n    - **screenshot** - Take a screenshot of the screen and use that.\n    - **Path** to png file - Use an image.\n\n-   **location**:       position\n      The place of the anchor on the monitor\n\n-   **anchor**:         anchor\n      The anchor position on the window\n\n-   **fullscreen**:     boolean Window is fullscreen.\n\n-   **width**:          distance The width of the window\n\n-   **x-offset**:       distance\n\n-   **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n-   **background-color**:  color\n\n-   **border-color**:      the color used for the border around the widget.\n\n-   **font**:              the font used by this textbox (string).\n\n-   **str**/**content**:   the string to display by this textbox (string).\n\n-   **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n-   **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n-   **text-color**:        the text color to use.\n\n-   **text-transform**:    text style {color} for the whole text.\n\n-   **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n-   **width**:             override the desired width for the textbox.\n\n-   **content**:           Set the displayed text (String).\n\n-   **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n-   **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n-   **placeholder-color**: Color of the placeholder text.\n\n-   **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n-   **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n-   **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n-   **cursor-width**:      The width of the cursor.\n\n-   **cursor-color**:      The color used to draw the cursor.\n\n-   **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n-   **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n-   **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n-   **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n-   **text-outline-width**: The width of the border around the text.  (Double)\n\n-   **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n-   **columns**:         integer Number of columns to show (at least 1)\n\n-   **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n-   **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n-   **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n-   **scrollbar-width**: distance Width of the scrollbar\n\n-   **cycle**:           boolean When navigating, it should wrap around\n\n-   **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n-   **lines**:           integer Number of rows to show in the list view.\n\n-   **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n-   **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n-   **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n-   **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n-   **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n-   0 or more `element` widgets of the type box.\n\n-   An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n-   Content - The content of the widget.\n\n-   Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n-   Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n-   Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling \n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` extension.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "mkdocs/docs/1.7.6/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n-   System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n-   Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n-   Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n\tdpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nDefault: *all*\n\n`-matching-negate-char` *char*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines. \n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n-   **-1**: the currently focused monitor.\n\n-   **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n-   **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n-   **-4**: the monitor with the focused window.\n\n-   **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n-   If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n-   If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes ` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n-   Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n-   Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n-   Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n-   Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n-   Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n-   Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- ` ` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n-   Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n-   drun: It uses the icon set in the desktop file.\n\n-   run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage. \n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared. \n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-sensible-terminal.1.markdown",
    "content": "# rofi-sensible-terminal(1)\n\n## NAME\n\n**rofi-sensible-terminal** -  launches $TERMINAL with fallbacks\n\n## SYNOPSIS\n\nrofi-sensible-terminal [arguments]\n\n## DESCRIPTION\n\nrofi-sensible-terminal is invoked in the rofi default config to start a terminal. This\nwrapper script is necessary since there is no distribution-independent terminal launcher\n(but for example Debian has x-terminal-emulator). Distribution packagers are responsible for\nshipping this script in a way which is appropriate for the distribution.\n\nIt tries to start one of the following (in that order):\n\n* `$TERMINAL` (this is a non-standard variable)\n* x-terminal-emulator\n* urxvt\n* rxvt\n* st\n* terminology\n* qterminal\n* Eterm\n* aterm\n* uxterm\n* xterm\n* roxterm\n* xfce4-terminal.wrapper\n* mate-terminal\n* lxterminal\n* konsole\n* alacritty\n* kitty\n* wezterm\n\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nDave Davenport and contributors\n\nCopied script from i3:\nMichael Stapelberg and contributors\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-theme-selector.1.markdown",
    "content": "# rofi-theme-selector(1)\n\n## NAME\n\n**rofi-theme-selector** - Preview and apply themes for **rofi**\n\n## DESCRIPTION\n\n**rofi-theme-selector** is a bash/rofi script to preview and apply themes for\n**rofi**. It's part of any installation of **rofi**.\n\n## USAGE\n\n### Running rofi-theme-selector\n\n**rofi-theme-selector** shows a list of all available themes in a **rofi**\nwindow. It lets you preview each theme with the Enter key and apply the theme\nto your **rofi** configuration file with Alt+a.\n\n## Theme directories\n\n**rofi-theme-selector** searches the following directories for themes:\n\n- ${PREFIX}/share/rofi/themes\n- $XDG_CONFIG_HOME/rofi/themes\n- $XDG_DATA_HOME/share/rofi/themes\n\n${PREFIX} reflects the install location of rofi. In most cases this will be\n\"/usr\".<br>\n$XDG_CONFIG_HOME is normally unset. Default path is \"$HOME/.config\".<br>\n$XDG_DATA_HOME is normally unset. Default path is \"$HOME/.local/share\".\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nQball Cow qball@gmpclient.org<br>\nRasmus Steinke rasi@xssn.at\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also specify the color and width of the cursor. You could, for example,\ncreate a crimson block cursor like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n\n- Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n- Format: url(\"path to image\");\n\n- Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n- Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n- Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n- Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n- Format: `#{HEX}{3}` (rgb)\n\n- Format: `#{HEX}{4}` (rgba)\n\n- Format: `#{HEX}{6}` (rrggbb)\n\n- Format: `#{HEX}{8}` (rrggbbaa)\n\n- Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n- Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n- Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n- Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n- `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n- `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n- `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n- `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n- `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\n\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\n\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue\n- `ceil`   : Round up lvalue to the next multiple of rvalue\n- `round`  : Round lvalue to the next multiple of rvalue\n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n- Format: `{Integer}`\n\n- Format: `{Distance}`\n\n- Format: `{Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  - `overlay`: the overlay widget.\n\n  - `mainbox`: The mainbox box.\n\n  - `inputbar`: The input bar box.\n    - `box`: the horizontal @box packing the widgets\n\n    - `case-indicator`: the case/sort indicator @textbox\n\n    - `prompt`: the prompt @textbox\n\n    - `entry`: the main entry @textbox\n\n    - `num-rows`: Shows the total number of rows.\n\n    - `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n    - `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n    - `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n  - `listview`: The listview.\n\n    - `scrollbar`: the listview scrollbar\n\n    - `element`: a box in the listview holding the entries\n\n      - `element-icon`: the widget in the listview's entry showing the\n   (optional) icon\n\n      - `element-index`: the widget in the listview's entry\n   keybindable index (1,2,3..0)\n\n      - `element-text`: the widget in the listview's entry showing the\n   text.\n\n  - `mode-switcher`: the main horizontal @box packing the buttons.\n    - `button`: the buttons @textbox for each mode\n\n  - `message`: The container holding the textbox.\n    - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n### all widgets\n\n- **enabled**:           enable/disable rendering of the widget\n\n- **padding**:           padding\n    Padding on the inside of the widget\n\n- **margin**:            padding\n    Margin on the outside of the widget\n\n- **border**:            border\n    Border around the widget (between padding and margin)/\n\n- **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n\n- **background-color**:  color\n    Background color\n\n- **background-image**:  image\n    Background image\n\n- **border-color**:      color\n    Color of the border\n\n- **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n- **font**:            string\n    The font used in the window\n\n- **transparency**:    string\n    Indicating if transparency should be used and what type:\n  - **real** - True transparency. Only works with a compositor.\n  - **background** - Take a screenshot of the background image and use that.\n  - **screenshot** - Take a screenshot of the screen and use that.\n  - **Path** to png file - Use an image.\n\n- **location**:       position\n      The place of the anchor on the monitor\n\n- **anchor**:         anchor\n      The anchor position on the window\n\n- **fullscreen**:     boolean Window is fullscreen.\n\n- **width**:          distance The width of the window\n\n- **x-offset**:       distance\n\n- **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n- **background-color**:  color\n\n- **border-color**:      the color used for the border around the widget.\n\n- **font**:              the font used by this textbox (string).\n\n- **str**/**content**:   the string to display by this textbox (string).\n\n- **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n- **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n- **text-color**:        the text color to use.\n\n- **text-transform**:    text style {color} for the whole text.\n\n- **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n- **width**:             override the desired width for the textbox.\n\n- **content**:           Set the displayed text (String).\n\n- **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n- **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n- **placeholder-color**: Color of the placeholder text.\n\n- **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n- **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n- **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n- **cursor-width**:      The width of the cursor.\n\n- **cursor-color**:      The color used to draw the cursor.\n\n- **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n- **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n- **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n- **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n- **text-outline-width**: The width of the border around the text.  (Double)\n\n- **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n\n- **columns**:         integer Number of columns to show (at least 1)\n\n- **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n- **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n- **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n- **scrollbar-width**: distance Width of the scrollbar\n\n- **cycle**:           boolean When navigating, it should wrap around\n\n- **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n- **lines**:           integer Number of rows to show in the list view.\n\n- **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n- **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n- **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n- **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n- **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n- 0 or more `element` widgets of the type box.\n\n- An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n>\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n- Content - The content of the widget.\n\n- Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n- Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n- Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling\n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\n\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.\nIt will first look for files with `.rasi`, then for files with `.rasinc`.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "mkdocs/docs/1.7.7/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n- System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n- Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n- Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n dpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\n\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nDefault: *all*\n\n`-matching-negate-char` *string*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable. It takes the first ASCII character from the string.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines.\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n- **-1**: the currently focused monitor.\n\n- **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n- **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n- **-4**: the monitor with the focused window.\n\n- **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n- If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n- If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n   }\n}\n```\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- `` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n- Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n- drun: It uses the icon set in the desktop file.\n\n- run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://developer.gnome.org/pygtk/stable/pango-markup-language.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared. \n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-sensible-terminal.1.markdown",
    "content": "# rofi-sensible-terminal(1)\n\n## NAME\n\n**rofi-sensible-terminal** -  launches $TERMINAL with fallbacks\n\n## SYNOPSIS\n\nrofi-sensible-terminal [arguments]\n\n## DESCRIPTION\n\nrofi-sensible-terminal is invoked in the rofi default config to start a terminal. This\nwrapper script is necessary since there is no distribution-independent terminal launcher\n(but for example Debian has x-terminal-emulator). Distribution packagers are responsible for\nshipping this script in a way which is appropriate for the distribution.\n\nIt tries to start one of the following (in that order):\n\n* `$TERMINAL` (this is a non-standard variable)\n* x-terminal-emulator\n* urxvt\n* rxvt\n* st\n* terminology\n* qterminal\n* Eterm\n* aterm\n* uxterm\n* xterm\n* roxterm\n* xfce4-terminal.wrapper\n* mate-terminal\n* lxterminal\n* konsole\n* alacritty\n* kitty\n* wezterm\n\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nDave Davenport and contributors\n\nCopied script from i3:\nMichael Stapelberg and contributors\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-theme-selector.1.markdown",
    "content": "# rofi-theme-selector(1)\n\n## NAME\n\n**rofi-theme-selector** - Preview and apply themes for **rofi**\n\n## DESCRIPTION\n\n**rofi-theme-selector** is a bash/rofi script to preview and apply themes for\n**rofi**. It's part of any installation of **rofi**.\n\n## USAGE\n\n### Running rofi-theme-selector\n\n**rofi-theme-selector** shows a list of all available themes in a **rofi**\nwindow. It lets you preview each theme with the Enter key and apply the theme\nto your **rofi** configuration file with Alt+a.\n\n## Theme directories\n\n**rofi-theme-selector** searches the following directories for themes:\n\n- ${PREFIX}/share/rofi/themes\n- $XDG_CONFIG_HOME/rofi/themes\n- $XDG_DATA_HOME/share/rofi/themes\n\n${PREFIX} reflects the install location of rofi. In most cases this will be\n\"/usr\".<br>\n$XDG_CONFIG_HOME is normally unset. Default path is \"$HOME/.config\".<br>\n$XDG_DATA_HOME is normally unset. Default path is \"$HOME/.local/share\".\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nQball Cow qball@gmpclient.org<br>\nRasmus Steinke rasi@xssn.at\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also specify the color and width of the cursor. You could, for example,\ncreate a crimson block cursor like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n\n- Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n- Format: url(\"path to image\");\n\n- Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n- Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n- Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n- Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n- Format: `#{HEX}{3}` (rgb)\n\n- Format: `#{HEX}{4}` (rgba)\n\n- Format: `#{HEX}{6}` (rrggbb)\n\n- Format: `#{HEX}{8}` (rrggbbaa)\n\n- Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n- Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n- Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n- Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n- `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n- `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n- `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n- `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n- `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\n\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\n\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue\n- `ceil`   : Round up lvalue to the next multiple of rvalue\n- `round`  : Round lvalue to the next multiple of rvalue\n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n- Format: `{Integer}`\n\n- Format: `{Distance}`\n\n- Format: `{Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  - `overlay`: the overlay widget.\n\n  - `mainbox`: The mainbox box.\n\n  - `inputbar`: The input bar box.\n    - `box`: the horizontal @box packing the widgets\n\n    - `case-indicator`: the case/sort indicator @textbox\n\n    - `prompt`: the prompt @textbox\n\n    - `entry`: the main entry @textbox\n\n    - `num-rows`: Shows the total number of rows.\n\n    - `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n    - `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n    - `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n  - `listview`: The listview.\n\n    - `scrollbar`: the listview scrollbar\n\n    - `element`: a box in the listview holding the entries\n\n      - `element-icon`: the widget in the listview's entry showing the\n   (optional) icon\n\n      - `element-index`: the widget in the listview's entry\n   keybindable index (1,2,3..0)\n\n      - `element-text`: the widget in the listview's entry showing the\n   text.\n\n  - `mode-switcher`: the main horizontal @box packing the buttons.\n    - `button`: the buttons @textbox for each mode\n\n  - `message`: The container holding the textbox.\n    - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n### all widgets\n\n- **enabled**:           enable/disable rendering of the widget\n\n- **padding**:           padding\n    Padding on the inside of the widget\n\n- **margin**:            padding\n    Margin on the outside of the widget\n\n- **border**:            border\n    Border around the widget (between padding and margin)/\n\n- **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n\n- **background-color**:  color\n    Background color\n\n- **background-image**:  image\n    Background image\n\n- **border-color**:      color\n    Color of the border\n\n- **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n- **font**:            string\n    The font used in the window\n\n- **transparency**:    string\n    Indicating if transparency should be used and what type:\n  - **real** - True transparency. Only works with a compositor.\n  - **background** - Take a screenshot of the background image and use that.\n  - **screenshot** - Take a screenshot of the screen and use that.\n  - **Path** to png file - Use an image.\n\n- **location**:       position\n      The place of the anchor on the monitor\n\n- **anchor**:         anchor\n      The anchor position on the window\n\n- **fullscreen**:     boolean Window is fullscreen.\n\n- **width**:          distance The width of the window\n\n- **x-offset**:       distance\n\n- **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n- **background-color**:  color\n\n- **border-color**:      the color used for the border around the widget.\n\n- **font**:              the font used by this textbox (string).\n\n- **str**/**content**:   the string to display by this textbox (string).\n\n- **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n- **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n- **text-color**:        the text color to use.\n\n- **text-transform**:    text style {color} for the whole text.\n\n- **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n- **width**:             override the desired width for the textbox.\n\n- **content**:           Set the displayed text (String).\n\n- **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n- **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n- **placeholder-color**: Color of the placeholder text.\n\n- **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n- **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n- **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n- **cursor-width**:      The width of the cursor.\n\n- **cursor-color**:      The color used to draw the cursor.\n\n- **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n- **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n- **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n- **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n- **text-outline-width**: The width of the border around the text.  (Double)\n\n- **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n\n- **columns**:         integer Number of columns to show (at least 1)\n\n- **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n- **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n- **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n- **scrollbar-width**: distance Width of the scrollbar\n\n- **cycle**:           boolean When navigating, it should wrap around\n\n- **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n- **lines**:           integer Number of rows to show in the list view.\n\n- **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n- **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n- **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n- **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n- **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n- 0 or more `element` widgets of the type box.\n\n- An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n>\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n- Content - The content of the widget.\n\n- Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n- Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n- Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling\n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\n\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.\nIt will first look for files with `.rasi`, then for files with `.rasinc`.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "mkdocs/docs/1.7.8/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n- System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n- Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n- Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n dpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\n\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nDefault: *all*\n\n`-matching-negate-char` *string*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable. It takes the first ASCII character from the string.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines.\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n- **-1**: the currently focused monitor.\n\n- **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n- **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n- **-4**: the monitor with the focused window.\n\n- **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n- If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n- If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n      /** Disable DBusActivatable */\n      DBusActivatable: false;\n   }\n}\n```\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- `` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n- Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n- drun: It uses the icon set in the desktop file.\n\n- run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-actions.5.markdown",
    "content": "# rofi-actions(5)\n\n## NAME\n\n**rofi-actions** - Custom commands following interaction with rofi menus\n\n## DESCRIPTION\n\n**rofi** allows to set custom commands or scripts to be executed when some actions are performed in the menu, such as changing selection, accepting an entry or canceling.\n\nThis makes it possible for example to play sound effects or read aloud menu entries on selection.\n\n## USAGE\n\nFollowing is the list of rofi flags for specifying custom commands or scripts to execute on supported actions:\n\n`-on-selection-changed` *cmd*\n\nCommand or script to run when the current selection changes. Selected text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-entry-accepted` *cmd*\n\nCommand or script to run when a menu entry is accepted. Accepted text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-mode-changed` *cmd*\n\nCommand or script to run when the menu mode (e.g. drun,window,ssh...) is changed.\n\n`-on-menu-canceled` *cmd*\n\nCommand or script to run when the menu is canceled.\n\n`-on-menu-error` *cmd*\n\nCommand or script to run when an error menu is shown (e.g. `rofi -e \"error message\"`). Error text is forwarded to the command replacing the pattern *{error}*.\n\n`-on-screenshot-taken` *cmd*\n\nCommand or script to run when a screenshot of rofi is taken. Screenshot path is forwarded to the command replacing the pattern *{path}*.\n\n### Example usage\n\nRofi command line:\n\n```bash\nrofi -on-selection-changed \"/path/to/select.sh {entry}\" \\\n     -on-entry-accepted \"/path/to/accept.sh {entry}\" \\\n     -on-menu-canceled \"/path/to/exit.sh\" \\\n     -on-mode-changed \"/path/to/change.sh\" \\\n     -on-menu-error \"/path/to/error.sh {error}\" \\\n     -on-screenshot-taken \"/path/to/camera.sh {path}\" \\\n     -show drun\n```\n\nRofi config file:\n\n```css\nconfiguration {\n    on-selection-changed: \"/path/to/select.sh {entry}\";\n    on-entry-accepted: \"/path/to/accept.sh {entry}\";\n    on-menu-canceled: \"/path/to/exit.sh\";\n    on-mode-changed: \"/path/to/change.sh\";\n    on-menu-error: \"/path/to/error.sh {error}\";\n    on-screenshot-taken: \"/path/to/camera.sh {path}\";\n}\n```\n\n### Play sound effects\n\nHere's an example bash script that plays a sound effect using `aplay` when the current selection is changed:\n\n```bash\n#!/bin/bash\n\ncoproc aplay -q $HOME/Music/selecting_an_item.wav\n```\n\nThe use of `coproc` for playing sounds is suggested, otherwise the rofi process will wait for sounds to end playback before exiting.\n\n### Read aloud\n\nHere's an example bash script that reads aloud currently selected entries using `espeak`:\n\n```bash\n#!/bin/bash\n\nkillall espeak\necho \"selected: $@\" | espeak\n```\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://docs.gtk.org/Pango/pango_markup.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n`kb-matcher-up`\n\nSelect the next matcher.\n\nDefault: Super+equal\n\n`kb-matcher-down`\n\nSelect the previous matcher.\n\nDefault: Super+minus\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **3**: Deleted an entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared.\n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also customize the cursor's color, width, and choose to hide it when the input box is empty. You could, for example, create a crimson block cursor that only appears when text is entered, like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n  hide-cursor-on-empty: true;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels and `hide-cursor-on-empty` is set to false.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n\n- Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n- Format: url(\"path to image\");\n\n- Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n- Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n- Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n- Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n- Format: `#{HEX}{3}` (rgb)\n\n- Format: `#{HEX}{4}` (rgba)\n\n- Format: `#{HEX}{6}` (rrggbb)\n\n- Format: `#{HEX}{8}` (rrggbbaa)\n\n- Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n- Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n- Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n- Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n- `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n- `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n- `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n- `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n- `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\n\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\n\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue\n- `ceil`   : Round up lvalue to the next multiple of rvalue\n- `round`  : Round lvalue to the next multiple of rvalue\n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n- Format: `{Integer}`\n\n- Format: `{Distance}`\n\n- Format: `{Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  - `overlay`: the overlay widget.\n\n  - `mainbox`: The mainbox box.\n\n  - `inputbar`: The input bar box.\n    - `box`: the horizontal @box packing the widgets\n\n    - `case-indicator`: the case/sort indicator @textbox\n\n    - `prompt`: the prompt @textbox\n\n    - `entry`: the main entry @textbox\n\n    - `num-rows`: Shows the total number of rows.\n\n    - `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n    - `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n    - `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n  - `listview`: The listview.\n\n    - `scrollbar`: the listview scrollbar\n\n    - `element`: a box in the listview holding the entries\n\n      - `element-icon`: the widget in the listview's entry showing the\n   (optional) icon\n\n      - `element-index`: the widget in the listview's entry\n   keybindable index (1,2,3..0)\n\n      - `element-text`: the widget in the listview's entry showing the\n   text.\n\n  - `mode-switcher`: the main horizontal @box packing the buttons.\n    - `button`: the buttons @textbox for each mode\n\n  - `message`: The container holding the textbox.\n    - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n### all widgets\n\n- **enabled**:           enable/disable rendering of the widget\n\n- **padding**:           padding\n    Padding on the inside of the widget\n\n- **margin**:            padding\n    Margin on the outside of the widget\n\n- **border**:            border\n    Border around the widget (between padding and margin)/\n\n- **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n- border-aa:  boolean\n    Disable aliasing on the border line. Disabling fixes some drawing issues because of nvidia broken driver workaround.\n\n- border-disable-nvidia-workaround: boolean\n    Disable work-around for nvidia driver breaking.\n\n- **background-color**:  color\n    Background color\n\n- **background-image**:  image\n    Background image\n\n- **border-color**:      color\n    Color of the border\n\n- **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n- **font**:            string\n    The font used in the window\n\n- **transparency**:    string\n    Indicating if transparency should be used and what type:\n  - **real** - True transparency. Only works with a compositor.\n  - **background** - Take a screenshot of the background image and use that.\n  - **screenshot** - Take a screenshot of the screen and use that.\n  - **Path** to png file - Use an image.\n\n- **location**:       position\n      The place of the anchor on the monitor\n\n- **anchor**:         anchor\n      The anchor position on the window\n\n- **fullscreen**:     boolean Window is fullscreen.\n\n- **width**:          distance The width of the window\n\n- **x-offset**:       distance\n\n- **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n- **handle-rounded-corners**:     boolean for rounded scrollbar\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n- **background-color**:  color\n\n- **border-color**:      the color used for the border around the widget.\n\n- **font**:              the font used by this textbox (string).\n\n- **str**/**content**:   the string to display by this textbox (string).\n\n- **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n- **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n- **text-color**:        the text color to use.\n\n- **text-transform**:    text style {color} for the whole text.\n\n- **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n- **width**:             override the desired width for the textbox.\n\n- **content**:           Set the displayed text (String).\n\n- **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n- **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n- **placeholder-color**: Color of the placeholder text.\n\n- **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n- **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n- **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n- **cursor-width**:      The width of the cursor.\n\n- **cursor-color**:      The color used to draw the cursor.\n\n- **hide-cursor-on-empty**: Hides the cursor when the search field is empty.\n    (Boolean)\n\n- **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n- **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n- **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n- **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n- **text-outline-width**: The width of the border around the text.  (Double)\n\n- **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n\n- **columns**:         integer Number of columns to show (at least 1)\n\n- **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n- **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n- **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n- **scrollbar-width**: distance Width of the scrollbar\n\n- **cycle**:           boolean When navigating, it should wrap around\n\n- **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n- **lines**:           integer Number of rows to show in the list view.\n\n- **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n- **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n- **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n- **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n- **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n### Overlay widget\n\n- **timeout**: The time the widget is visible when showing a temporary message.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n- 0 or more `element` widgets of the type box.\n\n- An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n>\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n- Content - The content of the widget.\n\n- Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n- Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n- Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling\n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\n\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.\nIt will first look for files with `.rasi`, then for files with `.rasinc`.\n\nIf you want to do an optional import, e.g. no error when the file does not exists, you can do:\n\n```css\n?import \"myfile\"\n```\n\nThis still throws an error on syntax error, but won't abort parsing if file does not exists.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "mkdocs/docs/1.7.9/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n- System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n- Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n- Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n dpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-case-smart`\n\nStart in case-smart mode behave like vim's `smartcase`, which determines\ncase-sensitivity by input.  When enabled, this will suppress `-case-sensitive`\nconfig.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\n\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nMultiple matching methods can be specified in a comma separated list.\nThe matching up/down keybinding allows cycling through at runtime.\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-exclude-categories` *category1*,*category2*\n\nExclude desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nDefault: *all*\n\n`-matching-negate-char` *string*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable. It takes the first ASCII character from the string.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines.\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n- **-1**: the currently focused monitor.\n\n- **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n- **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n- **-4**: the monitor with the focused window.\n\n- **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to the new theme file format. This overrides the old theme settings.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\n- If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n- If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n      /** Disable DBusActivatable */\n      DBusActivatable: false;\n   }\n}\n```\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- `` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n- Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n- drun: It uses the icon set in the desktop file.\n\n- run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-actions.5.markdown",
    "content": "# rofi-actions(5)\n\n## NAME\n\n**rofi-actions** - Custom commands following interaction with rofi menus\n\n## DESCRIPTION\n\n**rofi** allows to set custom commands or scripts to be executed when some actions are performed in the menu, such as changing selection, accepting an entry or canceling.\n\nThis makes it possible for example to play sound effects or read aloud menu entries on selection.\n\n## USAGE\n\nFollowing is the list of rofi flags for specifying custom commands or scripts to execute on supported actions:\n\n`-on-selection-changed` *cmd*\n\nCommand or script to run when the current selection changes. Selected text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-entry-accepted` *cmd*\n\nCommand or script to run when a menu entry is accepted. Accepted text is forwarded to the command replacing the pattern *{entry}*.\n\n`-on-mode-changed` *cmd*\n\nCommand or script to run when the menu mode (e.g. drun,window,ssh...) is changed.\n\n`-on-menu-canceled` *cmd*\n\nCommand or script to run when the menu is canceled.\n\n`-on-menu-error` *cmd*\n\nCommand or script to run when an error menu is shown (e.g. `rofi -e \"error message\"`). Error text is forwarded to the command replacing the pattern *{error}*.\n\n`-on-screenshot-taken` *cmd*\n\nCommand or script to run when a screenshot of rofi is taken. Screenshot path is forwarded to the command replacing the pattern *{path}*.\n\n### Example usage\n\nRofi command line:\n\n```bash\nrofi -on-selection-changed \"/path/to/select.sh {entry}\" \\\n     -on-entry-accepted \"/path/to/accept.sh {entry}\" \\\n     -on-menu-canceled \"/path/to/exit.sh\" \\\n     -on-mode-changed \"/path/to/change.sh\" \\\n     -on-menu-error \"/path/to/error.sh {error}\" \\\n     -on-screenshot-taken \"/path/to/camera.sh {path}\" \\\n     -show drun\n```\n\nRofi config file:\n\n```css\nconfiguration {\n    on-selection-changed: \"/path/to/select.sh {entry}\";\n    on-entry-accepted: \"/path/to/accept.sh {entry}\";\n    on-menu-canceled: \"/path/to/exit.sh\";\n    on-mode-changed: \"/path/to/change.sh\";\n    on-menu-error: \"/path/to/error.sh {error}\";\n    on-screenshot-taken: \"/path/to/camera.sh {path}\";\n}\n```\n\n### Play sound effects\n\nHere's an example bash script that plays a sound effect using `aplay` when the current selection is changed:\n\n```bash\n#!/bin/bash\n\ncoproc aplay -q $HOME/Music/selecting_an_item.wav\n```\n\nThe use of `coproc` for playing sounds is suggested, otherwise the rofi process will wait for sounds to end playback before exiting.\n\n### Read aloud\n\nHere's an example bash script that reads aloud currently selected entries using `espeak`:\n\n```bash\n#!/bin/bash\n\nkillall espeak\necho \"selected: $@\" | espeak\n```\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-debugging.5.markdown",
    "content": "# rofi-debugging(5)\n\n## NAME\n\nDebugging rofi.\n\nWhen reporting an issue with rofi crashing, or misbehaving. It helps to do some\nsmall test to help pin-point the problem.\n\nFirst try disabling your custom configuration: `-no-config`\n\nThis disables the parsing of the configuration files. This runs rofi in *stock*\nmode.\n\nIf you run custom C plugins, you can disable the plugins using: `-no-plugins`\n\n## Get the relevant information for an issue\n\nPlease pastebin the output of the following commands:\n\n```bash\nrofi -help\nrofi -dump-config\nrofi -dump-theme\n```\n\n`rofi -help`  provides us with the configuration files parsed, the exact\nversion, monitor layout and more useful information.\n\nThe `rofi -dump-config` and `rofi -dump-theme` output gives us `rofi`\ninterpretation of your configuration and theme.\n\nPlease check the output for identifiable information and remove this.\n\n## Timing traces\n\nTo get a timing trace, enable the **Timings** debug domain.\n\n```bash\nG_MESSAGES_DEBUG=Timings rofi -show drun\n```\nIt will show a trace with (useful) timing information at relevant points during\nthe execution. This will help debugging when rofi is slow to start.\n\nExample trace:\n\n```text\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000000 (0.000000): Started\n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000126 (0.000126): ../source/rofi.c:main:786 \n(process:14942): Timings-DEBUG: 13:47:39.335: 0.000163 (0.000037): ../source/rofi.c:main:819 \n(process:14942): Timings-DEBUG: 13:47:39.336: 0.000219 (0.000056): ../source/rofi.c:main:826 Setup Locale\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001235 (0.001016): ../source/rofi.c:main:828 Collect MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001264 (0.000029): ../source/rofi.c:main:830 Setup MODI\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001283 (0.000019): ../source/rofi.c:main:834 Setup mainloop\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001369 (0.000086): ../source/rofi.c:main:837 NK Bindings\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001512 (0.000143): ../source/xcb.c:display_setup:1177 Open Display\n(process:14942): Timings-DEBUG: 13:47:39.337: 0.001829 (0.000317): ../source/xcb.c:display_setup:1192 Setup XCB\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010650 (0.008821): ../source/rofi.c:main:844 Setup Display\n(process:14942): Timings-DEBUG: 13:47:39.346: 0.010715 (0.000065): ../source/rofi.c:main:848 Setup abe\n(process:14942): Timings-DEBUG: 13:47:39.350: 0.015101 (0.004386): ../source/rofi.c:main:883 Load cmd config \n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015275 (0.000174): ../source/rofi.c:main:907 Setup Modi\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015291 (0.000016): ../source/view.c:rofi_view_workers_initialize:1922 Setup Threadpool, start\n(process:14942): Timings-DEBUG: 13:47:39.351: 0.015349 (0.000058): ../source/view.c:rofi_view_workers_initialize:1945 Setup Threadpool, done\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032018 (0.016669): ../source/rofi.c:main:1000 Setup late Display\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032080 (0.000062): ../source/rofi.c:main:1003 Theme setup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032109 (0.000029): ../source/rofi.c:startup:668 Startup\n(process:14942): Timings-DEBUG: 13:47:39.367: 0.032121 (0.000012): ../source/rofi.c:startup:677 Grab keyboard\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032214 (0.000093): ../source/view.c:__create_window:701 xcb create window\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.032235 (0.000021): ../source/view.c:__create_window:705 xcb create gc\n(process:14942): Timings-DEBUG: 13:47:39.368: 0.033136 (0.000901): ../source/view.c:__create_window:714 create cairo surface\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033286 (0.000150): ../source/view.c:__create_window:723 pango cairo font setup\n(process:14942): Timings-DEBUG: 13:47:39.369: 0.033351 (0.000065): ../source/view.c:__create_window:761 configure font\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045896 (0.012545): ../source/view.c:__create_window:769 textbox setup\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045944 (0.000048): ../source/view.c:__create_window:781 setup window attributes\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045955 (0.000011): ../source/view.c:__create_window:791 setup window fullscreen\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045966 (0.000011): ../source/view.c:__create_window:797 setup window name and class\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045974 (0.000008): ../source/view.c:__create_window:808 setup startup notification\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045981 (0.000007): ../source/view.c:__create_window:810 done\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045992 (0.000011): ../source/rofi.c:startup:679 Create Window\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.045999 (0.000007): ../source/rofi.c:startup:681 Parse ABE\n(process:14942): Timings-DEBUG: 13:47:39.381: 0.046113 (0.000114): ../source/rofi.c:startup:684 Config sanity check\n(process:14942): Timings-DEBUG: 13:47:39.384: 0.048229 (0.002116): ../source/dialogs/run.c:get_apps:216 start\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054626 (0.006397): ../source/dialogs/run.c:get_apps:336 stop\n(process:14942): Timings-DEBUG: 13:47:39.390: 0.054781 (0.000155): ../source/dialogs/drun.c:get_apps:634 Get Desktop apps (start)\n(process:14942): Timings-DEBUG: 13:47:39.391: 0.055264 (0.000483): ../source/dialogs/drun.c:get_apps:641 Get Desktop apps (user dir)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082884 (0.027620): ../source/dialogs/drun.c:get_apps:659 Get Desktop apps (system dirs)\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082944 (0.000060): ../source/dialogs/drun.c:get_apps_history:597 Start drun history\n(process:14942): Timings-DEBUG: 13:47:39.418: 0.082977 (0.000033): ../source/dialogs/drun.c:get_apps_history:617 Stop drun history\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083638 (0.000661): ../source/dialogs/drun.c:get_apps:664 Sorting done.\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083685 (0.000047): ../source/view.c:rofi_view_create:1759 \n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083700 (0.000015): ../source/view.c:rofi_view_create:1783 Startup notification\n(process:14942): Timings-DEBUG: 13:47:39.419: 0.083711 (0.000011): ../source/view.c:rofi_view_create:1786 Get active monitor\n(process:14942): Timings-DEBUG: 13:47:39.420: 0.084693 (0.000982): ../source/view.c:rofi_view_refilter:1028 Filter start\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.085992 (0.001299): ../source/view.c:rofi_view_refilter:1132 Filter done\n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086090 (0.000098): ../source/view.c:rofi_view_update:982 \n(process:14942): Timings-DEBUG: 13:47:39.421: 0.086123 (0.000033): ../source/view.c:rofi_view_update:1002 Background\n(process:14942): Timings-DEBUG: 13:47:39.428: 0.092864 (0.006741): ../source/view.c:rofi_view_update:1008 widgets\n```\n\n## Debug domains\n\nTo further debug the plugin, you can get a trace with (lots of) debug\ninformation. This debug output can be enabled for multiple parts in rofi using\nthe glib debug framework. Debug domains can be enabled by setting the\nG\\_MESSAGES\\_DEBUG environment variable. At the time of creation of this page,\nthe following debug domains exist:\n\n- all: Show debug information from all domains.\n- X11Helper: The X11 Helper functions.\n- View: The main window view functions.\n- Widgets.Box: The Box widget.\n- Modes.DMenu: The dmenu mode.\n- Modes.Run: The run mode.\n- Modes.DRun: The desktop file run mode.\n- Modes.Window: The window mode.\n- Modes.Script: The script mode.\n- Modes.Combi: The script mode.\n- Modes.Ssh: The ssh mode.\n- Rofi: The main application.\n- Timings: Get timing output.\n- Theme: Theme engine debug output. (warning lots of output).\n- Widgets.Icon: The Icon widget.\n- Widgets.Box: The box widget.\n- Widgets.Container: The container widget.\n- Widgets.Window: The window widget.\n- Helpers.IconFetcher: Information about icon lookup.\n\nFor full list see `man rofi`.\n\nExample: `G_MESSAGES_DEBUG=Dialogs.DRun rofi -show drun` To get specific output\nfrom the Desktop file run dialog.\n\nTo redirect the debug output to a file (`~/rofi.log`) add:\n\n```bash\nrofi -show drun -log ~/rofi.log\n```\n\nSpecifying the logfile automatically enabled all log domains.\nThis can be useful when rofi is launched from a window manager.\n\n## Creating a backtrace\n\nFirst make sure you compile **rofi** with debug symbols:\n\n```bash\nmake CFLAGS=\"-O0 -g3\" clean rofi\n```\n\nGetting a backtrace using GDB is not very handy. Because if rofi get stuck, it\ngrabs keyboard and mouse. So if it crashes in GDB you are stuck. The best way\nto go is to enable core file. (ulimit -c unlimited in bash) then make rofi\ncrash. You can then load the core in GDB.\n\n```bash\ngdb rofi core\n```\n\nThen type inside gdb:\n\n```bash\nthread apply all bt\n```\n\nThe output trace is useful when reporting crashes.\n\nSome distribution have `systemd-coredump`, this way you can easily get a\nbacktrace via `coredumpctl`.\n\n## SEE ALSO\n\nrofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-script(5), rofi-keys(5),rofi-theme-selector(1)\n\n## AUTHOR\n\n* Qball Cow <qball@blame.services>\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-dmenu.5.markdown",
    "content": "# rofi-dmenu(5)\n\n## NAME\n\n**rofi dmenu mode** - Rofi dmenu emulation\n\n## DESCRIPTION\n\nTo integrate **rofi** into scripts as simple selection dialogs, \n**rofi** supports emulating **dmenu(1)** (A dynamic menu for X11).\n\nThe website for `dmenu` can be found [here](http://tools.suckless.org/dmenu/).\n\n**rofi** does not aim to be 100% compatible with `dmenu`. There are simply too\nmany flavors of `dmenu`. The idea is that the basic usage command-line flags\nare obeyed, theme-related flags are not. Besides, **rofi** offers some extended\nfeatures (like multi-select, highlighting, message bar, extra key bindings).\n\n## BASIC CONCEPT\n\nIn `dmenu` mode, **rofi** reads data from standard in, splits them into\nseparate entries and displays them. If the user selects a row, this is printed\nout to standard out, allowing the script to process it further.\n\nBy default separation of rows is done on new lines, making it easy to pipe the\noutput a one application into **rofi** and the output of rofi into the next.\n\n## USAGE \n\nBy launching **rofi** with the `-dmenu` flag it will go into dmenu emulation\nmode.\n\n```bash\nls | rofi -dmenu\n```\n\n### DMENU DROP-IN REPLACEMENT\n\nIf `argv[0]` (calling command) is dmenu, **rofi** will start in dmenu mode.\nThis way, it can be used as a drop-in replacement for dmenu. Just copy or\nsymlink **rofi** to dmenu in `$PATH`.\n\n```bash\nln -s /usr/bin/rofi /usr/bin/dmenu\n```\n\n### DMENU VS SCRIPT MODE\n\nScript mode is used to extend **rofi**, dmenu mode is used to extend a script.\nThe two do share much of the same input format. Please see the\n**rofi-script(5)** manpage for more information.\n\n### DMENU SPECIFIC COMMANDLINE FLAGS\n\nA lot of these options can also be modified by the script using special input.\nSee the **rofi-script(5)** manpage for more information about this syntax.\n\n`-sep` *separator*\n\nSeparator for `dmenu`. Example: To show a list of 'a' to 'e' with '|' as a\nseparator:\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu\n```\n\n`-p` *prompt*\n\nSpecify the prompt to show in `dmenu` mode. For example, select 'monkey',\na,b,c,d, or e.\n\n```bash\necho \"a|b|c|d|e\" | rofi -sep '|' -dmenu -p \"monkey\"\n```\n\nDefault: *dmenu*\n\n`-l` *number of lines to show*\n\nMaximum number of lines the menu may show before scrolling.\n\n```bash\nrofi -dmenu -l 25\n```\n\nDefault: *15*\n\n`-i`\n\nMakes `dmenu` searches case-insensitive\n\n`-a` *X*\n\nActive row, mark *X* as active. Where *X* is a comma-separated list of\npython(1)-style indices and ranges, e.g.  indices start at 0, -1 refers to the\nlast row with -2 preceding it, ranges are left-open and right-close, and so on.\nYou can specify:\n\n- A single row: '5'\n- A range of (last 3) rows: '-3:'\n- 4 rows starting from row 7: '7:11' (or in legacy notation: '7-10')\n- A set of rows: '2,0,-9'\n- Or any combination: '5,-3:,7:11,2,0,-9'\n\n`-u` *X*\n\nUrgent row, mark *X* as urgent. See `-a` option for details.\n\n`-only-match`\n\nOnly return a selected item, do not allow custom entry.\nThis mode always returns an entry. It will not return if no matching entry is\nselected.\n\n`-no-custom`\n\nOnly return a selected item, do not allow custom entry.\nThis mode returns directly when no entries given.\n\n`-format` *format*\n\nAllows the output of dmenu to be customized (N is the total number of input\nentries):\n\n- 's' selected string\n- 'i' index (0 - (N-1))\n- 'd' index (1 - N)\n- 'q' quote string\n- 'p' Selected string stripped from Pango markup (Needs to be a valid string)\n- 'f' filter string (user input)\n- 'F' quoted filter string (user input)\n\nDefault: 's'\n\n`-select` *string*\n\nSelect first line that matches the given string\n\n`-mesg` *string*\n\nAdd a message line below the filter entry box. Supports Pango markup. For more\ninformation on supported markup, see\n[here](https://docs.gtk.org/Pango/pango_markup.html)\n\n`-dump`\n\nDump the filtered list to stdout and quit.\nThis can be used to get the list as **rofi** would filter it.\nUse together with `-filter` command.\n\n`-input` *file*\n\nReads from *file* instead of stdin.\n\n`-password`\n\nHide the input text. This should not be considered secure!\n\n`-markup-rows`\n\nTell **rofi** that DMenu input is Pango markup encoded, and should be rendered.\nSee [here](https://docs.gtk.org/Pango/pango_markup.html)\nfor details about Pango markup.\n\n`-multi-select`\n\nAllow multiple lines to be selected. Adds a small selection indicator to the\nleft of each entry.\n\n`-sync`\n\nForce **rofi** mode to first read all data from stdin before showing the\nselection window. This is original dmenu behavior.\n\nNote: the default asynchronous mode will also be automatically disabled if used\nwith conflicting options,\nsuch as `-dump`, `-only-match` or `-auto-select`.\n\n`-window-title` *title*\n\nSet name used for the window title. Will be shown as Rofi - *title*\n\n`-w` *windowid*\n\nPosition **rofi** over the window with the given X11 window ID.\n\n`-keep-right`\n\nSet ellipsize mode to start. So, the end of the string is visible.\n\n`-display-columns`\n\nA comma seperated list of columns to show.\n\n`-display-column-separator`\n\nThe column separator. This is a regex. \n\n*default*: '\\t'\n\n`-ballot-selected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is selected.\n\n*default*: \"☑ \"\n\n`-ballot-unselected-str` *string*\n\nWhen multi-select is enabled, prefix this string when element is not selected.\n\n*default*: \"☐ \"\n\n`-ellipsize-mode` (start|middle|end)\n\nSet ellipsize mode on the listview.\n\n*default* \"end\"\n\n## PARSING ROW OPTIONS\n\nExtra options for individual rows can be also set. See the **rofi-script(5)**\nmanpage for details; the syntax and supported features are identical.\n\n## RETURN VALUE\n\n- **0**: Row has been selected accepted by user.\n- **1**: User cancelled the selection.\n- **10-28**: Row accepted by custom keybinding.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5), rofi-script(5),\nrofi-theme-selector(1), ascii(7)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-keys.5.markdown",
    "content": "# rofi-keys(5)\n\n## NAME\n\n**rofi keys** - Rofi Key and Mouse bindings\n\n## DESCRIPTION\n\n**rofi** supports overriding of any of it key and mouse binding.\n\n## Setting binding\n\nBindings can be done on the commandline (-{bindingname}):\n\n```bash\nrofi -show run -kb-accept-entry 'Control+Shift+space'\n```\n\nor via the configuration file:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space\";\n}\n```\n\nThe key can be set by its name (see above) or its keycode:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+[65]\";\n}\n```\n\nAn easy way to look up keycode is xev(1).\n\nMultiple keys can be specified for an action as a comma separated list:\n\n```css\nconfiguration {\n  kb-accept-entry: \"Control+Shift+space,Return\";\n}\n```\n\nBy Default **rofi** reacts on pressing, to act on the release of all keys\nprepend the binding with `!`:\n\n```css\nconfiguration {\n  kb-accept-entry: \"!Control+Shift+space,Return\";\n}\n```\n\n## Unsetting a binding\n\nTo unset a binding, pass an empty string.\n\n```css\nconfiguration {\n  kb-clear-line: \"\";\n}\n```\n\n## Keyboard Bindings\n\n`kb-primary-paste`\n\nPaste primary selection\n\nDefault:  Control+V,Shift+Insert\n\n`kb-secondary-paste`\n\nPaste clipboard\n\nDefault:  Control+v,Insert\n\n`kb-secondary-copy`\n\nCopy current selection to clipboard\n\nDefault:  Control+c\n\n`kb-clear-line`\n\nClear input line\n\nDefault:  Control+w\n\n`kb-move-front`\n\nBeginning of line\n\nDefault:  Control+a\n\n`kb-move-end`\n\nEnd of line\n\nDefault:  Control+e\n\n`kb-move-word-back`\n\nMove back one word\n\nDefault:  Alt+b,Control+Left\n\n`kb-move-word-forward`\n\nMove forward one word\n\nDefault:  Alt+f,Control+Right\n\n`kb-move-char-back`\n\nMove back one char\n\nDefault:  Left,Control+b\n\n`kb-move-char-forward`\n\nMove forward one char\n\nDefault:  Right,Control+f\n\n`kb-remove-word-back`\n\nDelete previous word\n\nDefault:  Control+Alt+h,Control+BackSpace\n\n`kb-remove-word-forward`\n\nDelete next word\n\nDefault:  Control+Alt+d\n\n`kb-remove-char-forward`\n\nDelete next char\n\nDefault:  Delete,Control+d\n\n`kb-remove-char-back`\n\nDelete previous char\n\nDefault:  BackSpace,Shift+BackSpace,Control+h\n\n`kb-remove-to-eol`\n\nDelete till the end of line\n\nDefault:  Control+k\n\n`kb-remove-to-sol`\n\nDelete till the start of line\n\nDefault:  Control+u\n\n`kb-accept-entry`\n\nAccept entry\n\nDefault:  Control+j,Control+m,Return,KP\\_Enter\n\n`kb-accept-custom`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Return\n\n`kb-accept-custom-alt`\n\nUse entered text as command (in ssh/run modes)\n\nDefault:  Control+Shift+Return\n\n`kb-accept-alt`\n\nUse alternate accept command.\n\nDefault:  Shift+Return\n\n`kb-delete-entry`\n\nDelete entry from history\n\nDefault:  Shift+Delete\n\n`kb-mode-next`\n\nSwitch to the next mode.\n\nDefault:  Shift+Right,Control+Tab\n\n`kb-mode-previous`\n\nSwitch to the previous mode.\n\nDefault:  Shift+Left,Control+ISO\\_Left\\_Tab\n\n`kb-mode-complete`\n\nStart completion for mode.\n\nDefault:  Control+l\n\n`kb-row-left`\n\nGo to the previous column\n\nDefault:  Control+Page\\_Up\n\n`kb-row-right`\n\nGo to the next column\n\nDefault:  Control+Page\\_Down\n\n`kb-row-up`\n\nSelect previous entry\n\nDefault:  Up,Control+p\n\n`kb-row-down`\n\nSelect next entry\n\nDefault:  Down,Control+n\n\n`kb-row-tab`\n\nGo to next row, if one left, accept it, if no left next mode.\n\nDefault:\n\n`kb-element-next`\n\nGo to next row.\n\nDefault: Tab\n\n`kb-element-prev`\n\nGo to previous row.\n\nDefault: ISO\\_Left\\_Tab\n\n`kb-page-prev`\n\nGo to the previous page\n\nDefault:  Page\\_Up\n\n`kb-page-next`\n\nGo to the next page\n\nDefault:  Page\\_Down\n\n`kb-row-first`\n\nGo to the first entry\n\nDefault:  Home,KP\\_Home\n\n`kb-row-last`\n\nGo to the last entry\n\nDefault:  End,KP\\_End\n\n`kb-row-select`\n\nSet selected item as input text\n\nDefault:  Control+space\n\n`kb-screenshot`\n\nTake a screenshot of the rofi window\n\nDefault:  Alt+S\n\n`kb-ellipsize`\n\nToggle between ellipsize modes for displayed data\n\nDefault:  Alt+period\n\n`kb-toggle-case-sensitivity`\n\nToggle case sensitivity\n\nDefault:  grave,dead\\_grave\n\n`kb-toggle-sort`\n\nToggle filtered menu sort\n\nDefault:  Alt+grave\n\n`kb-cancel`\n\nQuit rofi\n\nDefault:  Escape,Control+g,Control+bracketleft\n\n`kb-custom-1`\n\nCustom keybinding 1\n\nDefault:  Alt+1\n\n`kb-custom-2`\n\nCustom keybinding 2\n\nDefault:  Alt+2\n\n`kb-custom-3`\n\nCustom keybinding 3\n\nDefault:  Alt+3\n\n`kb-custom-4`\n\nCustom keybinding 4\n\nDefault:  Alt+4\n\n`kb-custom-5`\n\nCustom Keybinding 5\n\nDefault:  Alt+5\n\n`kb-custom-6`\n\nCustom keybinding 6\n\nDefault:  Alt+6\n\n`kb-custom-7`\n\nCustom Keybinding 7\n\nDefault:  Alt+7\n\n`kb-custom-8`\n\nCustom keybinding 8\n\nDefault:  Alt+8\n\n`kb-custom-9`\n\nCustom keybinding 9\n\nDefault:  Alt+9\n\n`kb-custom-10`\n\nCustom keybinding 10\n\nDefault:  Alt+0\n\n`kb-custom-11`\n\nCustom keybinding 11\n\nDefault:  Alt+exclam\n\n`kb-custom-12`\n\nCustom keybinding 12\n\nDefault:  Alt+at\n\n`kb-custom-13`\n\nCustom keybinding 13\n\nDefault:  Alt+numbersign\n\n`kb-custom-14`\n\nCustom keybinding 14\n\nDefault:  Alt+dollar\n\n`kb-custom-15`\n\nCustom keybinding 15\n\nDefault:  Alt+percent\n\n`kb-custom-16`\n\nCustom keybinding 16\n\nDefault:  Alt+dead\\_circumflex\n\n`kb-custom-17`\n\nCustom keybinding 17\n\nDefault:  Alt+ampersand\n\n`kb-custom-18`\n\nCustom keybinding 18\n\nDefault:  Alt+asterisk\n\n`kb-custom-19`\n\nCustom Keybinding 19\n\nDefault:  Alt+parenleft\n\n`kb-select-1`\n\nSelect row 1\n\nDefault:  Super+1\n\n`kb-select-2`\n\nSelect row 2\n\nDefault:  Super+2\n\n`kb-select-3`\n\nSelect row 3\n\nDefault:  Super+3\n\n`kb-select-4`\n\nSelect row 4\n\nDefault:  Super+4\n\n`kb-select-5`\n\nSelect row 5\n\nDefault:  Super+5\n\n`kb-select-6`\n\nSelect row 6\n\nDefault:  Super+6\n\n`kb-select-7`\n\nSelect row 7\n\nDefault:  Super+7\n\n`kb-select-8`\n\nSelect row 8\n\nDefault:  Super+8\n\n`kb-select-9`\n\nSelect row 9\n\nDefault:  Super+9\n\n`kb-select-10`\n\nSelect row 10\n\nDefault:  Super+0\n\n`kb-entry-history-up`\n\nGo up in the entry history.\n\nDefault:    Control+Up\n\n`kb-entry-history-down`\n\nGo down in the entry history.\n\nDefault:    Control+Down\n\n`kb-matcher-up`\n\nSelect the next matcher.\n\nDefault: Super+equal\n\n`kb-matcher-down`\n\nSelect the previous matcher.\n\nDefault: Super+minus\n\n## Mouse Bindings\n\n`ml-row-left`\n\nGo to the previous column\n\nDefault:  ScrollLeft\n\n`ml-row-right`\n\nGo to the next column\n\nDefault:  ScrollRight\n\n`ml-row-up`\n\nSelect previous entry\n\nDefault:  ScrollUp\n\n`ml-row-down`\n\nSelect next entry\n\nDefault:  ScrollDown\n\n`me-select-entry`\n\nSelect hovered row\n\nDefault:  MousePrimary\n\n`me-accept-entry`\n\nAccept hovered row\n\nDefault:  MouseDPrimary\n\n`me-accept-custom`\n\nAccept hovered row with custom action\n\nDefault:  Control+MouseDPrimary\n\n## Mouse key bindings\n\nThe following mouse buttons can be bound:\n\n* `Primary`: Primary (Left) mouse button click.\n* `Secondary`:  Secondary (Right) mouse button click.\n* `Middle`: Middle mouse button click.\n* `Forward`: The forward mouse button.\n* `Back`: The back mouse button.\n* `ExtraN`: The N'the mouse button. (Depending on mouse support).\n\nThe Identifier is constructed as follow:\n\n`Mouse<D><Button>`\n\n* `D` indicates optional Double press.\n* `Button` is the button name.\n\nSo `MouseDPrimary` is Primary (`Left`) mouse button double click.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), rofi-theme(5), rofi-script(5)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-script.5.markdown",
    "content": "# rofi-script(5)\n\n## NAME\n\n**rofi script mode** - Rofi format for scriptable mode.\n\n## DESCRIPTION\n\n**rofi** supports modes that use simple scripts in the background to generate a\nlist and process the result from user actions.  This provide a simple interface\nto make simple extensions to rofi.\n\n## USAGE\n\nTo specify a script mode, set a mode with the following syntax:\n\"{name}:{executable}\"\n\nFor example:\n\n```bash\nrofi -show fb -modes \"fb:file_browser.sh\"\n```\n\nThe name should be unique.\n\n## API\n\nRofi calls the executable without arguments on startup.  This should generate a\nlist of options, separated by a newline (`\\n`) (This can be changed by the\nscript). If the user selects an option, rofi calls the executable with the text\nof that option as the first argument. If the script returns no entries, rofi\nquits.\n\nA simple script would be:\n\n```bash\n#!/usr/bin/env bash\n\nif [ x\"$@\" = x\"quit\" ]\nthen\n    exit 0\nfi\necho \"reload\"\necho \"quit\"\n\n```\n\nThis shows two entries, reload and quit. When the quit entry is selected, rofi\ncloses.\n\n## Environment\n\nRofi sets the following environment variable when executing the script:\n\n### `ROFI_RETV`\n\nAn integer number with the current state:\n\n- **0**: Initial call of script.\n- **1**: Selected an entry.\n- **2**: Selected a custom entry.\n- **3**: Deleted an entry.\n- **10-28**: Custom keybinding 1-19 ( need to be explicitly enabled by script ).\n\n### `ROFI_INFO`\n\nEnvironment get set when selected entry get set with the property value of the\n'info' row option, if set.\n\n### `ROFI_DATA`\n\nEnvironment get set when script sets `data` option in header.\n\n## Passing mode options\n\nExtra options, like setting the prompt, can be set by the script. Extra options\nare lines that start with a NULL character (`\\0`) followed by a key, separator\n(`\\x1f`) and value.\n\nFor example to set the prompt:\n\n```bash\n    echo -en \"\\0prompt\\x1fChange prompt\\n\"\n```\n\nThe following extra options exists:\n\n-   **prompt**:      Update the prompt text.\n\n-   **message**:     Update the message text.\n\n-   **markup-rows**: If 'true' renders markup in the row.\n\n-   **urgent**:      Mark rows as urgent. (for syntax see the urgent option in\n    dmenu mode)\n\n-   **active**:      Mark rows as active. (for syntax see the active option in\n    dmenu mode)\n\n-   **delim**:       Set the delimiter for for next rows. Default is '\\n' and\n    this option should finish with this. Only call this on first call of script,\n    it is remembered for consecutive calls.\n\n-   **no-custom**:   If set to 'true'; only accept listed entries, ignore custom\n    input.\n\n-   **use-hot-keys**: If set to true, it enabled the Custom keybindings for\n    script. Warning this breaks the normal rofi flow.\n\n-   **keep-selection**: If set, the selection is not moved to the first entry,\n    but the current position is maintained. The filter is cleared.\n\n-   **keep-filter**: If set, the filter is not cleared.\n\n-   **new-selection**: If `keep-selection` is set, this allows you to override\n    the selected entry (absolute position).\n\n-   **data**:         Passed data to the next execution of the script via\n    **ROFI\\_DATA**.\n\n-   **theme**:       Small theme snippet to f.e. change the background color of\n    a widget.\n\nThe **theme** property cannot change the interface while running, it is only\nusable for small changes in, for example background color, of widgets that get\nupdated during display like the row color of the listview.\n\n## Parsing row options\n\nExtra options for individual rows can be set. The extra option can be specified\nfollowing the same syntax as mode option, but following the entry.\n\nFor example:\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\n\"\n```\n\nThe following options are supported:\n\n-   **icon**: Set the icon for that row.\n\n-   **display**: Replace the displayed string. (Original string will still be used for filtering)\n\n-   **meta**: Specify invisible search terms used for filtering.\n\n-   **nonselectable**: If true the row cannot activated.\n\n-   **permanent**: If true the row always shows, independent of filter.\n\n-   **info**: Info that, on selection, gets placed in the `ROFI_INFO`\n    environment variable. This entry does not get searched for filtering.\n\n-   **urgent**: Set urgent flag on entry (true/false)\n\n-   **active**: Set active flag on entry (true/false)\n\nmultiple entries can be passed using the `\\x1f` separator.\n\n```bash\n    echo -en \"aap\\0icon\\x1ffolder\\x1finfo\\x1ftest\\n\"\n```\n\n## Executing external program\n\nIf you want to launch an external program from the script, you need to make\nsure it is launched in the background. If not rofi will wait for its output (to\ndisplay).\n\nIn bash the best way to do this is using `coproc`.\n\n```bash\n coproc ( myApp  > /dev/null  2>&1 )\n```\n\n## DASH shell\n\nIf you use the `dash` shell for your script, take special care with how dash\nhandles escaped values for the separators. See issue #1201 on github.\n\n## Script locations\n\nTo specify a script there are the following options:\n\n- Specify an absolute path to the script.\n- The script is executable and located in your $PATH\n\nScripts located in the following location are **loaded** on startup\nand can be directly launched based on the filename (without extension):\n\n- The script is in `$XDG_CONFIG_HOME/rofi/scripts/`, this is usually\n  `~/.config/rofi/scripts/`.\n\nIf you have a script 'mymode.sh' in this folder you can open it using:\n\n```bash\nrofi -show mymode\n```\n\nSee `rofi -h` output for a list of detected scripts.\n\n## SEE ALSO\n\nrofi(1), rofi-sensible-terminal(1), dmenu(1), rofi-theme(5),\nrofi-theme-selector(1)\n\n## AUTHOR\n\nQball Cow <qball@gmpclient.org>\n\nRasmus Steinke <rasi@xssn.at>\n\nMorgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: Sean Pringle <sean.pringle@gmail.com>\n\nFor a full list of authors, check the AUTHORS file.\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-sensible-terminal.1.markdown",
    "content": "# rofi-sensible-terminal(1)\n\n## NAME\n\n**rofi-sensible-terminal** -  launches $TERMINAL with fallbacks\n\n## SYNOPSIS\n\nrofi-sensible-terminal [arguments]\n\n## DESCRIPTION\n\nrofi-sensible-terminal is invoked in the rofi default config to start a terminal. This\nwrapper script is necessary since there is no distribution-independent terminal launcher\n(but for example Debian has x-terminal-emulator). Distribution packagers are responsible for\nshipping this script in a way which is appropriate for the distribution.\n\nIt tries to start one of the following (in that order):\n\n* `$TERMINAL` (this is a non-standard variable)\n* x-terminal-emulator\n* urxvt\n* rxvt\n* st\n* terminology\n* qterminal\n* Eterm\n* aterm\n* uxterm\n* xterm\n* roxterm\n* xfce4-terminal.wrapper\n* mate-terminal\n* lxterminal\n* konsole\n* alacritty\n* kitty\n* wezterm\n* foot\n\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nDave Davenport and contributors\n\nCopied script from i3:\nMichael Stapelberg and contributors\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-theme-selector.1.markdown",
    "content": "# rofi-theme-selector(1)\n\n## NAME\n\n**rofi-theme-selector** - Preview and apply themes for **rofi**\n\n## DESCRIPTION\n\n**rofi-theme-selector** is a bash/rofi script to preview and apply themes for\n**rofi**. It's part of any installation of **rofi**.\n\n## USAGE\n\n### Running rofi-theme-selector\n\n**rofi-theme-selector** shows a list of all available themes in a **rofi**\nwindow. It lets you preview each theme with the Enter key and apply the theme\nto your **rofi** configuration file with Alt+a.\n\n## Theme directories\n\n**rofi-theme-selector** searches the following directories for themes:\n\n- ${PREFIX}/share/rofi/themes\n- $XDG_CONFIG_HOME/rofi/themes\n- $XDG_DATA_HOME/share/rofi/themes\n\n${PREFIX} reflects the install location of rofi. In most cases this will be\n\"/usr\".<br>\n$XDG_CONFIG_HOME is normally unset. Default path is \"$HOME/.config\".<br>\n$XDG_DATA_HOME is normally unset. Default path is \"$HOME/.local/share\".\n\n## SEE ALSO\n\nrofi(1)\n\n## AUTHORS\n\nQball Cow qball@gmpclient.org<br>\nRasmus Steinke rasi@xssn.at\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-theme.5.markdown",
    "content": "# rofi-theme(5)\n\n## NAME\n\n**rofi-theme** - Rofi theme format files\n\n## Getting started with theming\n\nThe easiest way to get started theming rofi is by modifying your existing theme.\n\nThemes can be modified/tweaked by adding theming elements to the end of the\\\nconfig file. The default location of this file is `~/.config/rofi/config.rasi`,\nif the file does not exists, you can create it.\n\nA basic config:\n\n```css\nconfiguration {\n  modes: [ combi ];\n  combi-modes: [ window, drun, run ];\n}\n\n@theme \"gruvbox-light\"\n \n/* Insert theme modifications after this */\n```\n\nFor example if we want to change the `Type to filter` text in the entry box we\nappend the following:\n\n```css\nentry {\n    placeholder: \"Type here\";\n}\n```\n\nIn the above section, `entry` indicates the widget, `placeholder` is the\nproperty we want to modify and we set it to the string `\"Type here\"`. To find\nthe commonly available widgets in rofi, see the 'Basic structure' section.\n\nTo change the mouse over cursor to a pointer, add:\n\n```css\nentry {\n    placeholder: \"Type here\";\n    cursor: pointer;\n}\n```\n\nFor the next modification, we want to add the icon after each text element and\nincrease the size. First we start by modifying the `element` widget:\n\n```css\n\nelement {\n  orientation: horizontal;\n  children: [ element-text, element-icon ];\n  spacing: 5px;\n}\n\n```\n\nResulting in the following packing:\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │ element─icon    │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nThe `element` (container) widget hold each entry in the `listview`, we add the\ntwo pre-defined children in the order we want to show. We also specify the\npacking direction (`orientation`) and the spacing between the children\n(`spacing`). We specify the space between the two children in absolute pixels\n(`px`).\n\nTo increase the icon-size, we need to modify the `element-icon` widget.\n\n```css\nelement-icon {\n    size: 2.5em;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │element─text                                 │ │    element      │ │ \n│ │                                             │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nIn this example we specify the size in the [em](https://www.w3.org/Style/LieBos3e/em) unit.\n\nNow lets change the text color of both the `entry` and the `element-text`\nwidget to red and background to blue.\n\n```css\nentry, element-text {\n  text-color: red;\n  background-color: rgb(0,0,255);\n}\n```\n\nHere we use two different methods of writing down the color, for `text-color`\nwe used a named color, for `background-color` we specify it in `rgb`.\nWe also specify the property for multiple widgets by passing a comma separated\nlist of widget names.\n\nIf you want to center the text relative to the icon, we can set this:\n\n```css\nelement-text {\n    vertical-align: 0.5;\n}\n```\n\n```text\n┌─────────────────────────────────────────────────────────────────────┐ \n│ element                                                             │ \n│ ┌─────────────────────────────────────────────┐ ┌─────────────────┐ │ \n│ │                                             │ │    element      │ │ \n│ │element-text                                 │ │       ─         │ │ \n│ │                                             │ │     icon        │ │ \n│ └─────────────────────────────────────────────┘ └─────────────────┘ │ \n└─────────────────────────────────────────────────────────────────────┘ \n```\n\nWe can also customize the cursor's color, width, and choose to hide it when the input box is empty. You could, for example, create a crimson block cursor that only appears when text is entered, like this:\n\n```css\nentry {\n  cursor-color: rgb(220,20,60);\n  cursor-width: 8px;\n  hide-cursor-on-empty: true;\n}\n```\n\nBy default, the `cursor-color` will be the same as the `text-color`. The\n`cursor-width` will always default to 2 pixels and `hide-cursor-on-empty` is set to false.\n\nIf you want to see the complete theme, including the modification you can run:\n\n```bash\nrofi -dump-theme\n```\n\n## Default theme loading\n\nBy default, rofi loads the default theme. This theme is **always** loaded.\nThe default configuration contains:\n\n```css\n@theme \"default\"\n```\n\nTo unload the default theme, and load another theme, add the `@theme` statement\nto your `config.rasi` file.\n\nIf you have a theme loaded via `@theme` or use the default theme, you can tweak\nit by adding overriding elements at the end of your `config.rasi` file.\n\nFor the difference between `@import` and `@theme` see the `Multiple file\nhandling` section in this manpage.\n\nTo see the default theme, run the following command:\n\n```bash\nrofi -no-config -dump-theme\n```\n\n## Description\n\nThe need for a new theme format was motivated by the fact that the way rofi\nhandled widgets has changed. From a very static drawing of lines and text to a\nnice structured form of packing widgets. This change made it possible to\nprovide a more flexible theme framework. The old theme format and config file\nare not flexible enough to expose these options in a user-friendly way.\nTherefore, a new file format has been created, replacing the old one.\n\n## Format specification\n\n## Encoding\n\nThe encoding of the file is UTF-8. Both unix (`\\n`) and windows (`\\r\\n`)\nnewlines format are supported. But unix is preferred.\n\n## Comments\n\nC and C++ file comments are supported.\n\n- Anything after  `//` and before a newline is considered a comment.\n\n- Everything between `/*` and `*/` is a comment, this comment can span\n    multiple lines.\n\nComments can be nested and the C comments can be inline.\n\nThe following is valid:\n\n```css\n// Magic comment.\nproperty: /* comment */ value;\n```\n\nHowever, this is not:\n\n```css\nprop/*comment*/erty: value;\n```\n\n## White space\n\nWhite space and newlines, like comments, are ignored by the parser.\n\nThis:\n\n```css\nproperty: name;\n```\n\nIs identical to:\n\n```css\n     property             :\nname\n\n;\n```\n\n## File extension\n\nThe preferred file extension for the new theme format is **rasi**. This is an\nabbreviation for **r**ofi **a**dvanced **s**tyle **i**nformation. If a theme\nfile is split over multiple files, include files can have the: **rasinc**\nextension.\n\n## Basic Structure\n\nEach element has a section with defined properties. Global properties can be\ndefined in section `* { }`. Sub-section names begin with an optional hash\nsymbol `#`.\n\nIt is advised to define the *global properties section* on top of the file to\nmake inheritance of properties clearer.\n\n```css\n/* Global properties section */\n* {\n    // list of properties\n}\n\n/* Element theme section. */\n{element path} {\n    // list of properties\n}\n{elements... } {\n    // list of properties\n}\n```\n\nIf there are multiple sections with the same name, they are merged. Duplicate\nproperties are overwritten and the last parsed entry kept.\n\n## Global properties section\n\nA theme can have one or more global properties sections. If there is more than\none, they will be merged.\n\nThe global properties section denotes the defaults for each element.\nEach property of this section can be referenced with `@{identifier}`\n(See Properties section)\n\nA global properties section is indicated with a `*` as element path.\n\n## Element theme section\n\nA theme can have multiple element theme sections.\n\nThe element path can consist of multiple names separated by whitespace or dots.\nEach element may contain any number of letters, numbers and `-`'s.\nThe first element in the element path can optionally start with a `#` (for\nhistoric reasons). Multiple elements can be specified by a `,`.\n\nThis is a valid element name:\n\n```css\nelement normal.normal {\n    background-color: blue;\n}\nbutton {\n    background-color: blue;\n}\n```\n\nAnd is identical to:\n\n```css\nelement normal normal, button {\n    background-color: blue;\n}\n```\n\nEach section inherits the global properties. Properties can be explicitly\ninherited from their parent with the `inherit` keyword.\nIn the following example:\n\n```css\nwindow {\n a: 1;\n b: 2;\n children: [ mainbox ];\n}\nmainbox {\n    a: inherit;\n    b: 4;\n    c: 8;\n}\n```\n\nThe element `mainbox` will have the following set of properties (if `mainbox`\nis a child of `window`):\n\n```css\na: 1;\nb: 4;\nc: 8;\n```\n\nIf multiple sections are defined with the same name, they are merged by the\nparser. If multiple properties with the same name are defined in one section,\nthe last encountered property is used.\n\n## Properties Format\n\nThe properties in a section consist of:\n\n```css\n{identifier}: {value};\n```\n\nBoth fields are mandatory for a property.\n\nThe `identifier` names the specified property. Identifiers can consist of any\ncombination of numbers, letters and '-'. It must not contain any whitespace.\nThe structure of the `value` defines the type of the property. The current\nparser does not define or enforce a certain type of a particular `identifier`.\nWhen used, values with the wrong type that cannot be converted are ignored.\n\nThe current theme format supports different types:\n\n- a string\n- an integer number\n- a fractional number\n- a boolean value\n- a color\n- image\n- text style\n- line style\n- a distance\n- a padding\n- a border\n- a position\n- a reference\n- an orientation\n- a cursor\n- a list of keywords\n- an array of values\n- an environment variable\n- Inherit\n\nSome of these types are a combination of other types.\n\n### String\n\n- Format:  `([\"'])[:print:]+\\1`\n\nStrings are always surrounded by double (`\"`) or single (`'`, apostrophe) quotes. Between\nthe quotes there can be any printable character.\n\nFor example:\n\n```css\nfont: \"Awasome 12\";\n```\n\nThe string must be valid UTF-8, special characters can be escaped:\n\n```css\ntext { content: \"Line one\\n\\tIndented line two 'Quoted text'\"; }\ntext { content: 'Line one\\n\\tIndented line two \"Quoted text\"'; }\ntext { content: \"Line one\\n\\tIndented line two \\\"Quoted text\\\"\"; }\n```\n\nThe following special characters can be escaped: `\\b`, `\\f`, `\\n`, `\\r`, `\\t`, `\\v`, `\\`,\n`\"` and `'` (double quotes inside single-quotes or in reverse don't need escape).\n\n### Integer\n\n- Format: `[-+]?[:digit:]+`\n\nAn integer may contain any number.\n\nFor examples:\n\n```css\nlines: 12;\n```\n\n### Real\n\n- Format: `[-+]?[:digit:]+(\\.[:digit:]+)?`\n\nA real is an integer with an optional fraction.\n\nFor example:\n\n```css\nreal: 3.4;\n```\n\nThe following is not valid: `.3`, `3.` or scientific notation: `3.4e-3`.\n\n### Boolean\n\n- Format: `(true|false)`\n\nBoolean value is either `true` or `false`. This is case-sensitive.\n\nFor example:\n\n```css\ndynamic: false;\n```\n\n### Image\n\n**rofi** support a limited set of background-image formats.\n\n- Format: url(\"path to image\");\n\n- Format: url(\"path to image\", scale);\n    where scale is: none, both, width, height\n\n- Format: linear-gradient(stop color,stop1, color, stop2 color, ...);\n\n- Format: linear-gradient(to direction, stop color,stop1, color, stop2 color,\n    ...); where direction is:   top,left,right,bottom.\n\n- Format: linear-gradient(angle, stop color,stop1, color, stop2 color, ...);\n    Angle in deg,rad,grad (as used in color).\n\nWhere the `path` is a string, and `stop` color is of type color.\n\n### Color\n\n**rofi** supports the color formats as specified in the CSS standard (1,2,3 and\nsome of CSS 4)\n\n- Format: `#{HEX}{3}` (rgb)\n\n- Format: `#{HEX}{4}` (rgba)\n\n- Format: `#{HEX}{6}` (rrggbb)\n\n- Format: `#{HEX}{8}` (rrggbbaa)\n\n- Format: `rgb[a]({INTEGER},{INTEGER},{INTEGER}[, {PERCENTAGE}])`\n\n- Format: `rgb[a]({INTEGER}%,{INTEGER}%,{INTEGER}%[, {PERCENTAGE}])`\n\n- Format: `hsl[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `hwb[a]( {ANGLE}, {PERCENTAGE}, {PERCENTAGE} [, {PERCENTAGE}])`\n\n- Format: `cmyk( {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE}, {PERCENTAGE} [,\n    {PERCENTAGE} ])`\n\n- Format: `{named-color} [ / {PERCENTAGE} ]`\n\nThe white-space format proposed in CSS4 is also supported.\n\nThe different values are:\n\n- `{HEX}` is a hexadecimal number ('0-9a-f' case insensitive).\n\n- `{INTEGER}` value can be between 0 and 255 or 0-100 when representing\n    percentage.\n\n- `{ANGLE}` is the angle on the color wheel, can be in `deg`, `rad`, `grad`\n    or `turn`. When no unit is specified, degrees is assumed.\n\n- `{PERCENTAGE}` can be between 0-1.0, or 0%-100%\n\n- `{named-color}` is one of the following colors:\n\n    AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black,\n    BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse,\n    Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue,\n    DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki,\n    DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon,\n    DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise,\n    DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue, FireBrick,\n    FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, GoldenRod,\n    Gray, Grey, Green, GreenYellow, HoneyDew, HotPink, IndianRed, Indigo,\n    Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue,\n    LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey,\n    LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue,\n    LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime,\n    LimeGreen, Linen, Magenta, Maroon, MediumAquaMarine, MediumBlue,\n    MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue,\n    MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue,\n    MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive,\n    OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenRod, PaleGreen,\n    PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum,\n    PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown,\n    Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue,\n    SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle,\n    Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow,\n    YellowGreen,transparent\n\nFor example:\n\n```css\nbackground-color: #FF0000;\nborder-color: rgba(0,0,1, 0.5);\ntext-color: SeaGreen;\n```\n\nor\n\n```css\nbackground-color: transparent;\ntext-color: Black;\n```\n\n### Text style\n\n- Format: `(bold|italic|underline|strikethrough|none)`\n\nText style indicates how the highlighted text is emphasized. `None` indicates\nthat no emphasis should be applied.\n\n- `bold`: make the text thicker then the surrounding text.\n- `italic`: put the highlighted text in script type (slanted).\n- `underline`: put a line under the text.\n- `strikethrough`: put a line through the text.\n\nThe following options are available on pango 1.50.0 and up:\n\n- `uppercase`: Uppercase the text.\n- `lowercase`: Lowercase the text.\n\nThe following option is disabled as pango crashes on this if there is eel\nupsizing or wrapping. This will be re-enabled once fixed:\n\n- `capitalize`: Capitalize the text.\n\n### Line style\n\n- Format: `(dash|solid)`\n\nIndicates how a line should be drawn.\nIt currently supports:\n\n- `dash`:  a dashed line, where the gap is the same width as the dash\n- `solid`: a solid line\n\n### Distance\n\n- Format: `{Integer}px`\n- Format: `{Real}em`\n- Format: `{Real}ch`\n- Format: `{Real}%`\n- Format: `{Real}mm`\n\nA distance can be specified in 3 different units:\n\n- `px`: Screen pixels.\n- `em`: Relative to text height.\n- `ch`: Relative to width of a single number.\n- `mm`: Actual size in millimeters (based on dpi).\n- `%`:  Percentage of the **monitor** size.\n\nDistances used in the horizontal direction use the monitor width. Distances in\nthe vertical direction use the monitor height.\nFor example:\n\n```css\n   padding: 10%;\n```\n\nOn a full-HD (1920x1080) monitor, it defines a padding of 192 pixels on the left\nand right side and 108 pixels on the top and bottom.\n\n#### Calculating sizes\n\nRofi supports some maths in calculating sizes. For this it uses the CSS syntax:\n\n```css\nwidth: calc( 100% - 37px );\n```\n\n```css\nwidth: calc( 20% min 512 );\n```\n\nIt supports the following operations:\n\n- `+`      : Add\n- `-`      : Subtract\n- `/`      : Divide\n- `-`      : Multiply\n- `modulo` : Modulo\n- `min`    : Minimum of lvalue or rvalue;\n- `max`    : Maximum of lvalue or rvalue;\n- `floor`  : Round down lvalue to the next multiple of rvalue\n- `ceil`   : Round up lvalue to the next multiple of rvalue\n- `round`  : Round lvalue to the next multiple of rvalue\n\nIt uses the C precedence ordering.\n\n### Padding\n\n- Format: `{Integer}`\n- Format: `{Distance}`\n- Format: `{Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance}`\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\nIf no unit is specified, pixels are assumed.\n\nThe different number of fields in the formats are parsed like:\n\n- 1 field: `all`\n- 2 fields: `top&bottom` `left&right`\n- 3 fields: `top`, `left&right`, `bottom`\n- 4 fields: `top`, `right`, `bottom`, `left`\n\n### Border\n\n- Format: `{Integer}`\n\n- Format: `{Distance}`\n\n- Format: `{Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Distance} {Distance} {Distance}`\n\n- Format: `{Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style}`\n\n- Format: `{Distance} {Line style} {Distance} {Line style} {Distance} {Line\n    style} {Distance} {Line style}`\n\nBorders are identical to padding, except that each distance field has a line\nstyle property.\n\n> When no unit is specified, pixels are assumed.\n\n### Position\n\nIndicate a place on the window/monitor.\n\n```text\n┌─────────────┬─────────────┬─────────────┐\n│ north west  │    north    │  north east │\n├─────────────┼─────────────┼─────────────┤\n│   west      │   center    │     east    │\n├─────────────┼─────────────┼─────────────┤\n│ south west  │    south    │  south east │\n└─────────────┴─────────────┴─────────────┘\n```\n\n- Format: `(center|east|north|west|south|north east|north west|south west|south\n  east)`\n\n### Visibility\n\nIt is possible to hide widgets:\n\n```css\ninputbar {\n    enabled: false;\n}\n```\n\n### Reference\n\n- Format: `@{PROPERTY NAME}`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property. For example, this is not valid:\n\n```css\nhighlight: bold @pink;\n```\n\nBut this is:\n\n```css\n* {\n    myhigh: bold #FAA;\n}\n\nwindow {\n    highlight: @myhigh;\n}\n```\n\n- Format: `var(PROPERTY NAME, DEFAULT)`\n\nA reference can point to another reference. Currently, the maximum number of\nredirects is 20. A property always refers to another property. It cannot be\nused for a subpart of the property.\n\nExample:\n\n```css\nwindow {\n    width: var( width, 30%);\n}\n```\n\nIf the property `width` is set globally (`*{}`) that value is used, if the\nproperty `width` is not set, the default value is used.\n\n### Orientation\n\n- Format: `(horizontal|vertical)`\n\nSpecify the orientation of the widget.\n\n### Cursor\n\n- Format: `(default|pointer|text)`\n\nSpecify the type of mouse cursor that is set when the mouse pointer is over the\nwidget.\n\n### List of keywords\n\n- Format: `[ keyword, keyword ]`\n\nA list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated. The `keyword` in the list refers to an widget name.\n\n### List of values\n\n- Format: `[ value, value, ... ]`\n\nAn list starts with a '[' and ends with a ']'. The entries in the list are\ncomma-separated.\n\n### Environment variable\n\n- Format: `${:alnum:}`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space.\n\n```css\n* {\n    background-color: ${BG};\n}\n```\n\n- Format: `env(ENVIRONMENT, default)`\n\nThis will parse the environment variable as the property value. (that then can\nbe any of the above types). The environment variable should be an alphanumeric\nstring without white-space. If the environment value is not found, the default\nvalue is used.\n\n```css\nwindow {\n    width: env(WIDTH, 40%);\n}\n```\n\nIf environment WIDTH is set, then that value is parsed, otherwise the default\nvalue (`40%`).\n\n### Inherit\n\n- Format: `inherit`\n\nInherits the property from its parent widget.\n\n```css\nmainbox {\n    border-color: inherit;\n}\n```\n\n## Elements paths\n\nElement paths exists of two parts, the first part refers to the actual widget\nby name. Some widgets have an extra state.\n\nFor example:\n\n```css\nelement selected {\n}\n```\n\nHere `element selected` is the name of the widget, `selected` is the state of\nthe widget.\n\nThe difference between dots and spaces is purely cosmetic. These are all the\nsame:\n\n```css\nelement .selected {\n\nelement.selected {\n}\nelement selected {\n}\n```\n\n### Supported element paths\n\n### Base widgets\n\nThe default widgets available in **rofi** and the default hierarchic:\n\n- `window`\n  - `overlay`: the overlay widget.\n\n  - `mainbox`: The mainbox box.\n\n  - `inputbar`: The input bar box.\n    - `box`: the horizontal @box packing the widgets\n\n    - `case-indicator`: the case/sort indicator @textbox\n\n    - `prompt`: the prompt @textbox\n\n    - `entry`: the main entry @textbox\n\n    - `num-rows`: Shows the total number of rows.\n\n    - `num-filtered-rows`: Shows the total number of rows after\n              filtering.\n\n    - `textbox-current-entry`: Shows the text of the currently selected\n              entry.\n\n    - `icon-current-entry`: Shows the icon of the currently selected\n              entry.\n\n  - `listview`: The listview.\n\n    - `scrollbar`: the listview scrollbar\n\n    - `element`: a box in the listview holding the entries\n\n      - `element-icon`: the widget in the listview's entry showing the\n   (optional) icon\n\n      - `element-index`: the widget in the listview's entry\n   keybindable index (1,2,3..0)\n\n      - `element-text`: the widget in the listview's entry showing the\n   text.\n\n  - `mode-switcher`: the main horizontal @box packing the buttons.\n    - `button`: the buttons @textbox for each mode\n\n  - `message`: The container holding the textbox.\n    - `textbox`: the message textbox\n\nNote that these path names match the default theme. Themes that provide a\ncustom layout will have different elements, and structure.\n\n### State\n\nState: State of widget\n\nOptional flag(s) indicating state of the widget, used for theming.\n\nThese are appended after the name or class of the widget.\n\n#### Example\n\n```\nbutton selected.normal { }\n\nelement selected.urgent { }\n```\n\nCurrently only the entrybox and scrollbar have states:\n\n#### Entrybox\n\n```\n{visible modifier}.{state}\n```\n\nWhere `visible modifier` can be:\n\n- normal: no modification\n- selected: the entry is selected/highlighted by user\n- alternate: the entry is at an alternating row (uneven row)\n\nWhere `state` is:\n\n- normal: no modification\n- urgent: this entry is marked urgent\n- active: this entry is marked active\n\nThese can be mixed.\n\nExample:\n\n```css\nnametotextbox selected.active {\n    background-color: #003642;\n    text-color: #008ed4;\n}\n```\n\nSets all selected textboxes marked active to the given text and background\ncolor. Note that a state modifies the original element, it therefore contains\nall the properties of that element.\n\n#### Scrollbar\n\nThe scrollbar uses the `handle` state when drawing the small scrollbar handle.\nThis allows the colors used for drawing the handle to be set independently.\n\n## Widget properties\n\nThe following properties are currently supported:\n\n### all widgets\n\n- **enabled**:           enable/disable rendering of the widget\n\n- **padding**:           padding\n    Padding on the inside of the widget\n\n- **margin**:            padding\n    Margin on the outside of the widget\n\n- **border**:            border\n    Border around the widget (between padding and margin)/\n\n- **border-radius**:     padding\n    Sets a radius on the corners of the borders.\n- border-aa:  boolean\n    Disable aliasing on the border line. Disabling fixes some drawing issues because of nvidia broken driver workaround.\n\n- border-disable-nvidia-workaround: boolean\n    Disable work-around for nvidia driver breaking.\n\n- **background-color**:  color\n    Background color\n\n- **background-image**:  image\n    Background image\n\n- **border-color**:      color\n    Color of the border\n\n- **cursor**:            cursor\n    Type of mouse cursor that is set when the mouse pointer is hovered over the\n    widget.\n\n### window\n\n- **font**:            string\n    The font used in the window\n\n- **transparency**:    string\n    Indicating if transparency should be used and what type:\n  - **real** - True transparency. Only works with a compositor.\n  - **background** - Take a screenshot of the background image and use that.\n  - **screenshot** - Take a screenshot of the screen and use that.\n  - **Path** to png file - Use an image.\n\n- **location**:       position\n      The place of the anchor on the monitor\n\n- **anchor**:         anchor\n      The anchor position on the window\n\n- **fullscreen**:     boolean Window is fullscreen.\n\n- **width**:          distance The width of the window\n\n- **x-offset**:       distance\n\n- **y-offset**:       distance The offset of the window to the anchor point,\n    allowing you to push the window left/right/up/down\n\n### scrollbar Properties\n\n- **background-color**:    color\n- **handle-width**:        distance\n- **handle-color**:        color\n- **border-color**:        color\n- **handle-rounded-corners**:     boolean for rounded scrollbar\n\n### box\n\n- **orientation**:      orientation Set the direction the elements are packed.\n- **spacing**:          distance Distance between the packed elements.\n\n### textbox\n\n- **background-color**:  color\n\n- **border-color**:      the color used for the border around the widget.\n\n- **font**:              the font used by this textbox (string).\n\n- **str**/**content**:   the string to display by this textbox (string).\n\n- **vertical-align**:    Vertical alignment of the text. A number between 0\n    (top) and 1 (bottom).\n\n- **horizontal-align**:  Horizontal alignment of the text. A number between 0\n    (left) and 1 (right).\n\n- **text-color**:        the text color to use.\n\n- **text-transform**:    text style {color} for the whole text.\n\n- **highlight**:         text style {color}. color is optional, multiple\n    highlight styles can be added like: bold underline italic #000000; This\n    option is only available on the `element-text` widget.\n\n- **width**:             override the desired width for the textbox.\n\n- **content**:           Set the displayed text (String).\n\n- **placeholder**:       Set the displayed text (String) when nothing is\n    entered.\n\n- **placeholder-markup**:       If true, placeholder text supports pango\n    markup for stylizing.\n\n- **placeholder-color**: Color of the placeholder text.\n\n- **blink**:             Enable/Disable blinking on an input textbox\n    (Boolean).\n\n- **markup**:            Force markup on, beware that only valid pango markup\n    strings are shown.\n\n- **tab-stops**:         array of distances. Set the location of tab stops by\n    their distance from the beginning of the line. Each distance should be\n    greater than the previous one. The text appears to the right of the tab\n    stop position (other alignments are not supported yet).\n\n- **cursor-width**:      The width of the cursor.\n\n- **cursor-color**:      The color used to draw the cursor.\n\n- **hide-cursor-on-empty**: Hides the cursor when the search field is empty.\n    (Boolean)\n\n- **cursor-outline**:      Enable a border (outline) around the cursor.\n    (Boolean)\n\n- **cursor-outline-width**: The width of the border around the cursor.\n    (Double)\n\n- **cursor-outline-color**: The color to use for the cursor outline.\n    (Color)\n\n- **text-outline**:      Enable a border (outline) around the text. (Boolean)\n\n- **text-outline-width**: The width of the border around the text.  (Double)\n\n- **text-outline-color**: The color to use for the text outline.    (Color)\n\n### listview\n\n- **columns**:         integer Number of columns to show (at least 1)\n\n- **fixed-height**:    boolean Always show `lines` rows, even if fewer\n    elements are available.\n\n- **dynamic**:         boolean `True` if the size should change when filtering\n    the list, `False` if it should keep the original height.\n\n- **scrollbar**:       boolean If the scrollbar should be enabled/disabled.\n\n- **scrollbar-width**: distance Width of the scrollbar\n\n- **cycle**:           boolean When navigating, it should wrap around\n\n- **spacing**:         distance Spacing between the elements (both vertical\n    and horizontal)\n\n- **lines**:           integer Number of rows to show in the list view.\n\n- **layout**:           orientation Indicate how elements are stacked.\n    Horizontal implements the dmenu style.\n\n- **reverse**:         boolean Reverse the ordering (top down to bottom up).\n\n- **flow**:           orientation The order the elements are layed out.\n    Vertical is the original 'column' view.\n\n- **fixed-columns**:    boolean Do not reduce the number of columns shown when\n    number of visible elements is not enough to fill them all.\n\n- **require-input**:    boolean Listview requires user input to be unhidden.\n    The list is still present and hitting accept will activate the first entry.\n\n### Overlay widget\n\n- **timeout**: The time the widget is visible when showing a temporary message.\n\n## Listview widget\n\nThe listview widget is special container widget.\nIt has the following fixed children widgets:\n\n- 0 or more `element` widgets of the type box.\n\n- An optional `scrollbar` widget. This can be enabled using the scrollbar\n    property.\n\nThese cannot be changed using the `children` property.\n\nEach Entry displayed by listview is captured by a `box` called `element`.\nAn `element` widget can contain the following special child widgets:\n\n- `element-icon`: An icon widget showing the icon associated to the entry.\n- `element-text`: A textbox widget showing the text associated to the entry.\n- `element-index`: A textbox widget that shows the shortcut keybinding number.\n\nBy default the `element-icon` and `element-text` child widgets are added to the\n`element`. This can be modified using the `children` property or the\n`[no]-show-icons` option.\n\nA child added with another name is treated the same as the special widget\ndescribed in the [advanced layout](#advanced-layout) section.\n\n### listview text highlight\n\nThe `element-text` widget in the `listview` is the one used to show the text.\nOn this widget set the `highlight` property (only place this property is used)\nto change the style of highlighting. The `highlight` property consist of the\n`text-style` property and a color.\n\nTo disable highlighting:\n\n```css\n  element-text {\n    highlight: None;\n  }\n```\n\nTo set to red underlined:\n\n```css\n  element-text {\n    highlight: underline red;\n  }\n```\n\n## Layout\n\nThe new format allows the layout of the **rofi** window to be tweaked\nextensively. For each widget, the themer can specify padding, margin, border,\nfont, and more. It even allows, as an advanced feature, to pack widgets in a\ncustom structure.\n\n### Basic layout structure\n\nThe whole view is made out of boxes that pack other boxes or widgets.\nThe box can be vertical or horizontal. This is loosely inspired by [GTK](http://gtk.org/).\n\nThe current layout of **rofi** is structured as follows:\n\n```text\n┌────────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                              │\n│ ┌───────────────────────────────────────────────────────────────────────────────┐  │\n│ │ mainbox  {BOX:vertical}                                                       │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ inputbar {BOX:horizontal}                                                 │ │  │\n│ │ │ ┌─────────┐ ┌─┐ ┌───────────────────────────────┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ │  │\n│ │ │ │ prompt  │ │:│ │ entry                         │ │#fr│ │ / │ │#ns│ │ci │ │ │  │\n│ │ │ └─────────┘ └─┘ └───────────────────────────────┘ └───┘ └───┘ └───┘ └───┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ message                                                                   │ │  │\n│ │ │ ┌───────────────────────────────────────────────────────────────────────┐ │ │  │\n│ │ │ │ textbox                                                               │ │ │  │\n│ │ │ └───────────────────────────────────────────────────────────────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │ listview                                                                  │ │  │\n│ │ │ ┌─────────────────────────────────────────────────────────────────────┐   │ │  │\n│ │ │ │ element                                                             │   │ │  │\n│ │ │ │ ┌─────────────────┐ ┌─────────────────────────────────────────────┐ │   │ │  │\n│ │ │ │ │element─icon     │ │element─text                                 │ │   │ │  │\n│ │ │ │ └─────────────────┘ └─────────────────────────────────────────────┘ │   │ │  │\n│ │ │ └─────────────────────────────────────────────────────────────────────┘   │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ │                                                                               │  │\n│ │ ┌───────────────────────────────────────────────────────────────────────────┐ │  │\n│ │ │  mode─switcher {BOX:horizontal}                                           │ │  │\n│ │ │ ┌───────────────┐   ┌───────────────┐  ┌──────────────┐ ┌───────────────┐ │ │  │\n│ │ │ │ Button        │   │ Button        │  │ Button       │ │ Button        │ │ │  │\n│ │ │ └───────────────┘   └───────────────┘  └──────────────┘ └───────────────┘ │ │  │\n│ │ └───────────────────────────────────────────────────────────────────────────┘ │  │\n│ └───────────────────────────────────────────────────────────────────────────────┘  │\n└────────────────────────────────────────────────────────────────────────────────────┘\n\n\n```\n>\n> - ci is the case-indicator\n> - fr is the num-filtered-rows\n> - ns is the num-rows\n\n### Error message structure\n\n```text\n┌──────────────────────────────────────────────────────────────────────────────────┐\n│ window {BOX:vertical}                                                            │\n│ ┌─────────────────────────────────────────────────────────────────────────────┐  │\n│ │ error─message {BOX:vertical}                                                │  │\n│ │ ┌────────────────────────────────────────────────────────────────────────┐  │  │\n│ │ │ textbox                                                                │  │  │\n│ │ └────────────────────────────────────────────────────────────────────────┘  │  │\n│ └─────────────────────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────────────────────┘\n\n```\n\n### Advanced layout\n\nThe layout of **rofi** can be tweaked by packing the 'fixed' widgets in a\ncustom structure.\n\nThe following widgets are fixed, as they provide core **rofi** functionality:\n\n- prompt\n- entry\n- overlay\n- case-indicator\n- message\n- listview\n- mode-switcher\n- num-rows\n- num-filtered-rows\n\nThe following keywords are defined and can be used to automatically pack a\nsubset of the widgets. These are used in the default theme as depicted in the\nfigure above.\n\n- mainbox Packs: `inputbar, message, listview, mode-switcher`\n- inputbar Packs: `prompt,entry,case-indicator`\n\nAny widget name starting with `textbox` is a textbox widget, others are box\nwidgets and can pack other widgets.\n\nThere are several special widgets that can be used by prefixing the name of the\nwidget:\n\n#### Textbox widget\n\nThis is a read-only textbox widget. The displayed string can be set with `content`.\n\nExample:\n\n```css\ntextbox-custom {\n  expand: false;\n  content: \"My Message\";\n}\n```\n\n#### Icon\n\nThis is an icon widget. The displayed icon can be set with `filename` and size\nwith `size`. If the property `action` is set, it acts as a button. `action` can\nbe set to a keybinding name and completes that action. (see rofi -show keys for\na list).\n\nIf the `squared` property is set to **false** the widget height and width are\nnot forced to be equal.\n\nExample:\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### button\n\nThis is a textbox widget that can have a 'clickable' action. The `action` can\nbe set to: `keybinding`: accepts a keybinding name and completes that action.\n(see rofi -show keys for a list).\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n#### Children\n\nTo specify children, set the `children`\nproperty (this always happens on the `box` child, see example below):\n\n```css\ninputbar {\n  children: [prompt,entry,overlay,case-indicator];\n}\n```\n\nThe theme needs to be updated to match the hierarchy specified.\n\nBelow is an example of a theme emulating dmenu:\n\n```css\n* {\n    background-color:      Black;\n    text-color:            White;\n    border-color:          White;\n    font:            \"Times New Roman 12\";\n}\n\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\n\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\n\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      10;\n}\n\nentry {\n    expand:     false;\n    width:      10em;\n}\n\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n```\n\n### Padding and margin\n\nJust like CSS, **rofi** uses the box model for each widget.\n\n```text\n┌──────────────────────────────────────────────────────────────────┐\n│ margin                                                           │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │ border                                                     │  │\n│  │ ┌────────────────────────────────────────────────────────┐ │  │\n│  │ │ padding                                                │ │  │\n│  │ │ ┌────────────────────────────────────────────────────┐ │ │  │\n│  │ │ │ content                                            │ │ │  │\n│  │ │ └────────────────────────────────────────────────────┘ │ │  │\n│  │ └────────────────────────────────────────────────────────┘ │  │\n│  └────────────────────────────────────────────────────────────┘  │\n└──────────────────────────────────────────────────────────────────┘\n```\n\nExplanation of the different parts:\n\n- Content - The content of the widget.\n\n- Padding - Clears an area around the widget. The padding shows the\n    background color of the widget.\n\n- Border - A border that goes around the padding and content. The border use\n    the border-color of the widget.\n\n- Margin - Clears an area outside the border. The margin is transparent.\n\nThe box model allows us to add a border around elements, and to define space\nbetween elements.\n\nThe size of each margin, border, and padding can be set.\nFor the border, a linestyle and radius can be set.\n\n### Spacing\n\nWidgets that can pack more then one child widget (currently box and listview)\nhave the `spacing` property. This property sets the distance between the packed\nwidgets (both horizontally and vertically).\n\n```text\n┌───────────────────────────────────────┐\n│ ┌────────┐ s ┌────────┐ s ┌────────┐  │\n│ │ child  │ p │ child  │ p │ child  │  │\n│ │        │ a │        │ a │        │  │\n│ │        │ c │        │ c │        │  │\n│ │        │ i │        │ i │        │  │\n│ │        │ n │        │ n │        │  │\n│ └────────┘ g └────────┘ g └────────┘  │\n└───────────────────────────────────────┘\n```\n\n### Advanced box packing\n\nMore dynamic spacing can be achieved by adding dummy widgets, for example to\nmake one widget centered:\n\n```text\n┌────────────────────────────────────────────────────┐\n│  ┌───────────────┐  ┌────────┐  ┌───────────────┐  │\n│  │ dummy         │  │ child  │  │ dummy         │  │\n│  │ expand: true; │  │        │  │ expand: true; │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  │               │  │        │  │               │  │\n│  └───────────────┘  └────────┘  └───────────────┘  │\n└────────────────────────────────────────────────────┘\n```\n\nIf both dummy widgets are set to expand, `child` will be centered. Depending on\nthe `expand` flag of child the remaining space will be equally divided between\nboth dummy and child widget (expand enabled), or both dummy widgets (expand\ndisabled).\n\n## Debugging\n\nTo get debug information from the parser, run rofi like:\n\n```bash\nG_MESSAGES_DEBUG=Parser rofi -show run\n```\n\nSyntax errors are shown in a popup and printed out to command line with the\nabove command.\n\nTo see the elements queried during running, run:\n\n```bash\nG_MESSAGES_DEBUG=Theme rofi -show run\n```\n\nTo test minor changes, part of the theme can be passed on the command line, for\nexample to set it to full-screen:\n\n```bash\nrofi -theme-str 'window { fullscreen:true;}' -show run\n```\n\nAnother syntax to modify theme properties is:\n\n```bash\nrofi -theme+window+fullscreen true -show run\n```\n\nTo print the current theme, run:\n\n```bash\nrofi -dump-theme\n```\n\n## Media support\n\nParts of the theme can be conditionally loaded, like the CSS `@media` option.\n\n```css\n@media ( min-width: 120 ) {\n\n}\n```\n\nIt supports the following keys as constraint:\n\n- `min-width`:         load when width is bigger or equal then value.\n- `max-width`:         load when width is smaller then value.\n- `min-height`:        load when height is bigger or equal then value.\n- `max-height`:        load when height is smaller then value.\n- `min-aspect-ratio`   load when aspect ratio is over value.\n- `max-aspect-ratio`:  load when aspect ratio is under value.\n- `monitor-id`:        The monitor id, see rofi -help for id's.\n- `enabled`:           Boolean option to enable. Supports environment variable\n  or DMENU to detect if in dmenu mode.\n\n@media takes an integer number or a fraction, for integer number `px` can be\nadded.\n\n```css\n@media ( min-width: 120 px ) {\n\n}\n```\n\n```css\n@media ( enabled: env(DO_LIGHT, false )) {\n\n}\n```\n\n```css\n@media ( enabled: DMENU) {\n\n}\n```\n\n## Conflicting constraints\n\nIt is possible to define conflicting constraints in the theme. These conflicts\nare not explicitly reported. The most common example is forcing a specific\nwindow size, for example by enabling full-screen mode, having number of lines\nset in the listview and having the listview expand to available space. There is\nclearly a conflict in these 3 constraints. In this case, listview will not\nlimit to the number of lines, but tries to fill the available space. It is up\nto the theme designer to make sure the theme handles this correctly.\n\n## Font Parsing\n\nRofi uses [pango](https://pango.gnome.org/) for font rendering. The font should\nbe specified in a format that pango understands. This normally is the font name\nfollowed by the font size. For example:\n\n```text\nmono 18\n```\n\nOr\n\n```text\nFontAwesome 22\n```\n\nFrom the pango manpage:\n\nThe string must have the form\n\n```text\n\\[FAMILY-LIST] \\[STYLE-OPTIONS] \\[SIZE] \\[VARIATIONS]\n```\n\nwhere FAMILY-LIST is a comma-separated list of families optionally terminated\nby a comma, STYLE\\_OPTIONS is a whitespace-separated list of words where each\nword describes one of style, variant, weight, stretch, or gravity, and SIZE is\na decimal number (size in points) or optionally followed by the unit modifier\n“px” for absolute size. VARIATIONS is a comma-separated list of font variation\nspecifications of the form “`axis`=value” (the = sign is optional).\n\nThe following words are understood as styles: \"Normal”, “Roman”, “Oblique”,\n“Italic”.\n\nThe following words are understood as variants: “Small-Caps”, “All-Small-Caps”,\n“Petite-Caps”, “All-Petite-Caps”, “Unicase”, “Title-Caps”.\n\nThe following words are understood as weights: “Thin”, “Ultra-Light”,\n“Extra-Light”, “Light”, “Semi-Light”, “Demi-Light”, “Book”, “Regular”,\n“Medium”, “Semi-Bold”, “Demi-Bold”, “Bold”, “Ultra-Bold”, “Extra-Bold”,\n“Heavy”, “Black”, “Ultra-Black”, “Extra-Black”.\n\nThe following words are understood as stretch values: “Ultra-Condensed”,\n“Extra-Condensed”, “Condensed”, “Semi-Condensed”, “Semi-Expanded”, “Expanded”,\n“Extra-Expanded”, “Ultra-Expanded”.\n\nThe following words are understood as gravity values: “Not-Rotated”, “South”,\n“Upside-Down”, “North”, “Rotated-Left”, “East”, “Rotated-Right”, “West”.\n\nAny one of the options may be absent. If FAMILY-LIST is absent, then the\nfamily\\_name field of the resulting font description will be initialized to\nNULL. If STYLE-OPTIONS is missing, then all style options will be set to the\ndefault values. If SIZE is missing, the size in the resulting font description\nwill be set to 0.\n\nA typical example:\n\n\"Cantarell Italic Light 15 \\`wght`=200\"\n\n## Icon Handling\n\nRofi supports 3 ways of specifying an icon:\n\n- Filename\n- icon-name, this is looked up via the icon-theme.\n- Markup String. It renders a string as an icon.\n\nFor the first two options, GdkPixbuf is used to open and render the icons.\nThis in general gives support for most required image formats.\nFor the string option it uses Pango to render the string. The string needs to\nstart with a `<span` tag, that allows you to set color and font.\n\nMarkup string:\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='red'>⏻</span>\" | ./rofi -dmenu\n```\n\nGetting supported icon formats:\n\n```bash\nG_MESSAGES_DEBUG=Helpers.IconFetcher rofi\n```\n\nThis uses the debug framework and prints out a list of supported image  file\nextensions.\n\n## Multiple file handling\n\nThe rasi file format offers two methods of including other files. This can be\nused to modify existing themes, or have multiple variations on a theme.\n\n- import:  Import and parse a second file.\n- theme:   Discard theme, and load file as a fresh theme.\n\nSyntax:\n\n```css\n@import \"myfile\"\n@theme \"mytheme\"\n```\n\nThe commandline option `-theme` is handled similarly to `@theme`.\n\nThe specified file can either by *name*, *filename*,*full path*.\n\nIf a filename is provided, it will try to resolve it in the following order:\n\n- If path is absolute and file exists, it will open the file. This includes expansion of '~' or '~user'\n- On an `@import` or `@theme` it looks in the directory of the file that tried to include it.\n- `${XDG_CONFIG_HOME}/rofi/themes/`\n- `${XDG_CONFIG_HOME}/rofi/`\n- `${XDG_DATA_HOME}/rofi/themes/`\n- `${INSTALL PREFIX}/share/rofi/themes/`\n\nA name is resolved (if it has no valid extension) as a filename by appending the `.rasi` and the `.rasinc` extension.\nIt will first look for files with `.rasi`, then for files with `.rasinc`.\n\nIf you want to do an optional import, e.g. no error when the file does not exists, you can do:\n\n```css\n?import \"myfile\"\n```\n\nThis still throws an error on syntax error, but won't abort parsing if file does not exists.\n\n## Examples\n\nSeveral examples are installed together with **rofi**. These can be found in\n`{datadir}/rofi/themes/`, where `{datadir}` is the install path of **rofi**\ndata. When installed using a package manager, this is usually: `/usr/share/`.\n\n## SEE ALSO\n\nrofi(1), rofi-script(5), rofi-theme-selector(1)\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi-thumbnails.5.markdown",
    "content": "# rofi-thumbnails(5)\n\n## NAME\n\n**rofi-thumbnails** - Rofi thumbnails system\n\n## DESCRIPTION\n\n**rofi** is now able to show thumbnails for all file types where an XDG compatible thumbnailer is present in the system.\n\nThis is done by default in filebrowser and recursivebrowser mode, if **rofi** is launched with the `-show-icons` argument.\n\nIn a custom user script or dmenu mode, it is possible to produce entry icons using XDG thumbnailers by adding the prefix `thumbnail://` to the filename\nspecified after `\\0icon\\x1f`, for example:\n\n```bash\necho -en \"EntryName\\0icon\\x1fthumbnail://path/to/file\\n\" | rofi -dmenu -show-icons\n```\n\n### XDG thumbnailers\n\nXDG thumbnailers are files with a \".thumbnailer\" suffix and a structure similar to \".desktop\" files for launching applications. They are placed in `/usr/share/thumbnailers/` or `$HOME/.local/share/thumbnailers/`, and contain a list of mimetypes, for which is possible to produce the thumbnail image, and a string with the command to create said image. The example below shows the content of `librsvg.thumbnailer`, a thumbnailer for svg files using librsvg:\n\n```\n[Thumbnailer Entry]\nTryExec=/usr/bin/gdk-pixbuf-thumbnailer\nExec=/usr/bin/gdk-pixbuf-thumbnailer -s %s %u %o\nMimeType=image/svg+xml;image/svg+xml-compressed;\n```\n\nThe images produced are named as the md5sum of the input files and placed, depending on their size, in the XDG thumbnails directories: `$HOME/.cache/thumbnails/{normal,large,x-large,xx-large}`. They are then loaded by **rofi** as entry icons and can also be used by file managers like Thunar, Caja or KDE Dolphin to show their thumbnails. Additionally, if a thumbnail for a file is found in the thumbnails directories (produced previously by **rofi** or a file manager), **rofi** will load it instead of calling the thumbnailer.\n\nIf a suitable thumbnailer for a given file is not found, **rofi** will try to use the corresponding mimetype icon from the icon theme. \n\n### Custom command to create thumbnails\n\nIt is possible to use a custom command to generate thumbnails for generic entry names, for example a script that downloads an icon given its url or selects different icons depending on the input. This can be done providing the `-preview-cmd` argument followed by a string with the command to execute, with the following syntax:\n\n```\nrofi ... -preview-cmd 'path/to/script_or_cmd \"{input}\" \"{output}\" \"{size}\"'\n```\n\n**rofi** will call the script or command substituting `{input}` with the input entry icon name (the string after `\\0icon\\x1fthumbnail://`), `{output}` with the output filename of the thumbnail and `{size}` with the requested thumbnail size. The script or command is responsible of producing a thumbnail image (if possible respecting the requested size) and saving it in the given `{output}` filename.\n\n### Issues with AppArmor\n\nIn Linux distributions using AppArmor (such as Ubuntu and Debian), the default rules shipped can cause issues with thumbnails generation. If that is the case, AppArmor can be disabled by issuing the following commands\n\n```\nsudo systemctl stop apparmor\nsudo systemctl disable apparmor\n```\n\nIn alternative, the following apparmor profile con be placed in a file named /etc/apparmor.d/usr.bin.rofi\n\n```\n#vim:syntax=apparmor\n# AppArmor policy for rofi\n\n#include <tunables/global>\n\n/usr/bin/rofi {\n    #include <abstractions/base>\n\n    # TCP/UDP network access for NFS\n    network inet  stream,\n    network inet6 stream,\n    network inet  dgram,\n    network inet6 dgram,\n\n    /usr/bin/rofi mr,\n\n    @{HOME}/ r,\n    @{HOME}/** rw,\n    owner @{HOME}/.cache/thumbnails/** rw,\n}\n```\n\nthen run\n\n```\napparmor_parser  -r /etc/apparmor.d/usr.bin.rofi\n```\n\nto reload the rule. This assumes that **rofi** binary is in /usr/bin, that is the case of a standard package installation.\n"
  },
  {
    "path": "mkdocs/docs/2.0.0/rofi.1.markdown",
    "content": "# rofi(1)\n\n## NAME\n\n**rofi** - A window switcher, application launcher, ssh dialog, dmenu\nreplacement and more\n\n## SYNOPSIS\n\n**rofi** [ -show *mode* ]|[ -dmenu ]|[ -e *msg* ] [ CONFIGURATION ]\n\n## DESCRIPTION\n\n**rofi** is an X11 pop-up window switcher, run dialog, dmenu replacement, and\nmore. It focuses on being fast to use and have minimal distraction. It supports\nkeyboard and mouse navigation, type to filter, tokenized search and more.\n\n## USAGE\n\n**rofi**'s main functionality is to assist in your workflow, allowing you to\nquickly switch between windows, start applications or log into a remote machine\nvia `ssh`. There are different *modes* for different types of actions. **rofi**\nis a standalone application and should not be integrated into scripts. For\nintegration into scripts it has a special mode that functions as a (drop-in)\nreplacement for **dmenu(1)**. See emulating dmenu below.\n\n### Running rofi\n\nTo launch **rofi** directly in a certain mode, specify a mode with `rofi -show\n<mode>`. To show the `drun` dialog:\n\n```bash\n    rofi -show drun\n```\n\nA useful setup in minimalistic window managers is to combine `drun`, `run`\nwith `window` mode:\n\n```bash\n  rofi -show combi -modes combi -combi-modes \"window,drun,run\"\n```\n\nIn this setup it first list all open applications, then all installed\napplications. So if you type firefox and hit return, it will switch to the\nrunning firefox, or launch it when it is not running.\n\n### Emulating dmenu\n\n**rofi** can emulate **dmenu(1)** (a dynamic menu for X11) when launched with\nthe `-dmenu` flag.\n\nFor more information see **rofi-dmenu(5)**.\n\n### Display Error message\n\n**rofi** error dialog can also be called from the command line.\n\n```bash\n    rofi -e \"my message\"\n```\n\nMarkup support can be enabled, see CONFIGURATION options.\n\n## CONFIGURATION\n\nThere are currently three methods of setting configuration options (evaluated\nin order below):\n\n- System configuration file  (for example `/etc/rofi.rasi`). It first checks\n    `XDG_CONFIG_DIRS`, and then `SYSCONFDIR` (that is passed at compile time).\n    It loads the first config file it finds, it does not merge multiple system\n    configuration files.\n\n- Rasi theme file: The new *theme* format can be used to set configuration\n    values.\n\n- Command-line options: Arguments passed to **rofi**.\n\nTo get a template config file, run: `rofi -dump-config > config.rasi`\n\nThis will contain (commented) all current configuration options, modified\noptions are uncommented.\n\nTo get a template config file that sets the icon-theme run: `rofi -icon-theme\nhicolor -dump-config`.\n\nIt is **strongly** recommended to use this as a starting point for your\nconfiguration.\n\nAn empty configuration section in the config file looks like:\n\n```css\nconfiguration {\n // set config options here\n}\n```\n\nMost of the configuration options mentioned below (beside options like `-show`,\n`-dump-config` that apply to a single run) can be set here.\n\nFor example to set the dpi value to 72:\n\n```css\nconfiguration {\n dpi: 72;\n}\n```\n\nThe configuration system supports the following types:\n\n- string\n- integer (signed and unsigned)\n- char\n- boolean\n- lists\n\nFor the syntax of these options, see the **rofi-theme(5)** manpage.\n\nFor use on the command line, Boolean options have a non-default command-line\nsyntax. Example to enable option X:\n\n```text\n    -X\n```\n\nTo disable option X:\n\n```text\n    -no-X\n```\n\nBelow is a list of the most important options:\n\n### General\n\n`-help`\n\nThe help option shows the full list of command-line options and the current set\nvalues. These include dynamic (run-time generated) options.\n\n`-info`\n\nThe info option shows useful information to include when reporting an issue.\nThis includes compile time options, detected monitors and more. Please check\nthe output for any personal information before posting online.\n\n`-version`\n\nShow the **rofi** version and exit.\n\n`-dump-config`\n\nDump the current active configuration, in rasi format, to stdout and exit.\nInformation about the rasi format can be found in the **rofi-theme(5)** manpage.\n\n`-dump-theme`\n\nDump the current active theme, in rasi format, to stdout and exit.\n\n`-rasi-validate` *filename*\n\nTry to parse the file and return 0 when successful, non-zero when failed.\n\n`-list-keybindings`\n\nList all known keybindings without trying to parse them. This can be used to\nlook for duplicate bindings.\n\n`-threads` *num*\n\nSpecify the number of threads **rofi** should use:\n\n- 0: Autodetect the number of supported hardware threads.\n- 1: Disable threading\n- 2..n: Specify the maximum number of threads to use in the thread pool.\n\nDefault:  Autodetect\n\n`-display` *display*\n\nThe X server to contact. Default is `$DISPLAY`.\n\n`-dmenu`\n\nRun **rofi** in dmenu mode. This allows for interactive scripts.\nIn `dmenu` mode, **rofi** reads from STDIN, and output to STDOUT.\nA simple example, displaying three pre-defined options:\n\n```bash\n    echo -e \"Option #1\\nOption #2\\nOption #3\" | rofi -dmenu\n```\n\nOr get the options from a script:\n\n```bash\n    ~/my_script.sh | rofi -dmenu\n```\n\nSee the **rofi-dmenu(5)** manpage for more information.\n\n`-show` *mode*\n\nOpen **rofi** in a certain mode. Available modes are `window`, `run`, `drun`,\n`ssh`, `combi`. The special argument `keys` can be used to open a searchable\nlist of supported key bindings\n(see the **rofi-keys(5)** manpage)\n\nTo show the run-dialog:\n\n```bash\n    rofi -show run\n```\n\nIf `-show` is the last option passed to rofi, the first enabled modes is shown.\n\n`-modes` *mode1,mode2*\n\nSpecify an ordered, comma-separated list of modes to enable.\nEnabled modes can be changed at runtime. Default key is `Ctrl+Tab`.\nIf no modes are specified, all configured modes will be enabled.\nTo only show the `run` and `ssh` launcher:\n\n```bash\n    rofi -modes \"run,ssh\" -show run\n```\n\nCustom modes can be added using the internal `script` mode. Each such mode has\ntwo parameters:\n\n```text\n<name>:<script>\n```\n\nExample: Have a mode called 'Workspaces' using the `i3_switch_workspaces.sh`\nscript:\n\n```bash\n    rofi -modes \"window,run,ssh,Workspaces:i3_switch_workspaces.sh\" -show Workspaces\n```\n\nNotes: The i3 window manager dislikes commas in the command when specifying an\nexec command. For that case, `#` can be used as a separator.\n\n**TIP**: The name is allowed to contain spaces:\n\n```bash\n    rofi -modes \"My File Browser:fb.sh\" -show \"My File Browser\"\n```\n\n`-case-sensitive`\n\nStart in case-sensitive mode. This option can be changed at run-time using the\n`-kb-toggle-case-sensitivity` key binding.\n\n`-case-smart`\n\nStart in case-smart mode behave like vim's `smartcase`, which determines\ncase-sensitivity by input.  When enabled, this will suppress `-case-sensitive`\nconfig.\n\n`-cycle`\n\nCycle through the result list. Default is 'true'.\n\n`-filter` *filter*\n\nFilter the list by setting text in input bar to *filter*\n\n`-config` *filename*\n\nLoad an alternative configuration file.\n\n`-cache-dir` *filename*\n\nDirectory that is used to place temporary files, like history.\n\n`-scroll-method` *method*\n\nSelect the scrolling method. 0: Per page, 1: continuous.\n\n`-normalize-match`\n\nNormalize the string before matching, so `o` will match `ö`, and `é` matches\n`e`.  This is not a perfect implementation, but works. For now, it disables\nhighlighting of the matched part.\n\n`-no-lazy-grab`\n\nDisables lazy grab, this forces the keyboard being grabbed before gui is shown.\n\n`-no-plugins`\n\nDisable plugin loading.\n\n`-plugin-path` *directory*\n\nSpecify the directory where **rofi** should look for plugins.\n\n`-show-icons`\n\nShow application icons in `drun` and `window` modes.\n\n`-icon-theme`\n\nSpecify icon theme to be used. If not specified default theme from DE is used,\n*Adwaita* and *gnome* themes act as fallback themes.\n\n`-markup`\n\nUse Pango markup to format output wherever possible.\n\n`-normal-window`\n\nMake **rofi** react like a normal application window. Useful for scripts like\nClerk that are basically an application.\n\n`-transient-window`\n\nMake **rofi** react like a modal dialog that is transient to the currently\nfocused window. Useful when you use a keyboard shortcut to run and show\non the window you are working with.\n\n`-[no-]steal-focus`\n\nMake rofi steal focus on launch and restore close to window that held it when\nlaunched.\n\n`-refilter-timeout-limit`\n\nThe time (in ms) boundary filter may take before switch from instant to delayed\nfilter mode.\n\nDefault: 300\n\nA fallback icon can be specified for each mode:\n\n```css\nconfiguration {\n    <mode>{\n      fallback-icon: \"<icon name>\";\n    }\n}\n```\n\nExample\n\n```css\nconfiguration {\n    run,drun {\n      fallback-icon: \"application-x-addon\";\n    }\n}\n```\n\n### Matching\n\n`-matching` *method*\n\nSpecify the matching algorithm used.\nCurrently, the following methods are supported:\n\n- **normal**: match the int string\n- **regex**: match a regex input\n- **glob**: match a glob pattern\n- **fuzzy**: do a fuzzy match\n- **prefix**: match prefix\n\nDefault: *normal*\n\nMultiple matching methods can be specified in a comma separated list.\nThe matching up/down keybinding allows cycling through at runtime.\n\nNote: glob matching might be slow for larger lists\n\n`-tokenize`\n\nTokenize the input.\n\n`-drun-categories` *category1*,*category2*\n\nOnly show desktop files that are present in the listed categories.\n\n`-drun-exclude-categories` *category1*,*category2*\n\nExclude desktop files that are present in the listed categories.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using `drun`, match only with the specified Desktop entry fields.\nThe different fields are:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **all**: all the above\n\nDefault: *name,generic,exec,categories,keywords*\n\n`-drun-display-format`\n\nThe format string for the `drun` dialog:\n\n- **name**: the application's name\n- **generic**: the application's generic name\n- **exec**: the application's  executable\n- **categories**: the application's categories\n- **comment**: the application comment\n- **url**: The url in case of a link type desktop file\n\nPango markup can be used to formatting the output.\n\nDefault: `{name} [<span weight='light' size='small'><i>({generic})</i></span>]`\n\nNote: Only fields enabled in `-drun-match-fields` can be used in the format\nstring.\n\n`-[no-]drun-show-actions`\n\nShow actions present in the Desktop files.\n\nDefault: false\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n- **title**: window's title\n- **class**: window's class\n- **role**: window's role\n- **name**: window's name\n- **desktop**: window's current desktop\n- **all**: all the above\n\nFor Wayland, the list of accepted fields is different:\n\n- **title**: window's title\n- **app-id**: Wayland Application ID or XWayland window's class\n- **class**: same as app-id\n- **all**: all of the above\n\nDefault: *all*\n\n`-matching-negate-char` *string*\n\nSet the character used to negate the query (i.e. if it does **not** match the\nnext keyword). Set to '\\x0' to disable. It takes the first ASCII character from the string.\n\nDefault: '-'\n\n### Filtered menu sort\n\n`-[no]-sort`\n\nEnable, disable sort for filtered menu.\nThis setting can be changed at runtime (see `-kb-toggle-sort`).\n\n`-sorting-method` 'method' to specify the sort method.\n\nThere are 2 methods:\n\n- **levenshtein** (Default)\n- **fzf**\n\n### Layout and Theming\n\n**IMPORTANT:** In newer **rofi** releases, all the theming options have been\nmoved into the new theme format. They are no longer normal **rofi** options\nthat can be passed directly on the command line (there are too many). Small\nsnippets can be passed on the command line: `rofi -theme-str 'window {width:\n50%;}'` to override a single setting. They are merged into the current theme.\nThey can also be appended at the end of the **rofi** config file to override\nparts of the theme.\n\nMost of the following options are **deprecated** and should not be used. Please\nuse the new theme format to customize **rofi**. More information about the new\nformat can be found in the **rofi-theme(5)** manpage.\n\n`-location`\n\nSpecify where the window should be located. The numbers map to the following\nlocations on screen:\n\n```text\n      1 2 3\n      8 0 4\n      7 6 5\n```\n\nDefault: *0*\n\n`-fixed-num-lines`\n\nKeep a fixed number of visible lines.\n\n`-sidebar-mode`\n\nOpen in sidebar-mode. In this mode, a list of all enabled modes is shown at the\nbottom (See `-modes` option). To show sidebar, use:\n\n```bash\n    rofi -show run -sidebar-mode \n```\n\n`-hover-select`\n\nAutomatically select the entry the mouse is hovering over. This option is best\ncombined with custom mouse bindings. To utilize hover-select and accept an\nentry in a single click, use:\n\n```bash\n    rofi -show run -hover-select -me-select-entry '' -me-accept-entry MousePrimary\n```\n\n`-eh` *number*\n\nSet row height (in chars)\nDefault: *1*\n\n`-auto-select`\n\nWhen one entry is left, automatically select it.\n\n`-m` *num*,  `-m` *name*, `-monitor` *num*, `-monitor` *name*\n\nSelect monitor to display **rofi** on. It accepts as input: *primary* (if\nprimary output is set), the *xrandr* output name, or integer number (in order\nof detection). Negative numbers are handled differently:\n\n- **-1**: the currently focused monitor.\n\n- **-2**: the currently focused window (that is, **rofi** will be displayed\n    on top of the focused window).\n\n- **-3**: Position of mouse (overrides the location setting to get normal\n    context menu behavior.)\n\n- **-4**: the monitor with the focused window.\n\n- **-5**: the monitor that shows the mouse pointer.\n\nDefault: *-5*\n\nSee `rofi -h` output for the detected monitors, their position, and size.\n\n`-theme` *filename*\n\nPath to theme file, or name of an installed theme. See **rofi-theme(5)** manpage\non how themes are resolved.\n\n`-theme-str` *string*\n\nAllow theme parts to be specified on the command line as an override.\n\nFor example:\n\n```bash\n    rofi -theme-str '#window { fullscreen: true; }'\n```\n\nThis option can be specified multiple times.\nThis is now the method to tweak the theme via the command line.\n\n`-dpi`  *number*\n\nOverride the default DPI setting.\n\nOn X11:\n\n- If set to `0`, it tries to auto-detect based on X11 screen size (similar to\n    i3 and GTK).\n\n- If set to `1`, it tries to auto-detect based on the size of the monitor\n    that **rofi** is displayed on (similar to latest Qt 5).\n\nOn Wayland:\n\n- If set to `0` or `1`, it tries to auto-detect if there is one monitor, or if\nthere is a `-monitor` name specified.\n\n`-selected-row` *selected row*\n\nSelect a certain row.\n\nDefault: *0*\n\n### PATTERN setting\n\n`-terminal`\n\nSpecify which terminal to start.\n\n```bash\n    rofi -terminal xterm\n```\n\nPattern: *{terminal}*\n\nDefault: *x-terminal-emulator*\n\n`-ssh-client` *client*\n\nOverride the used `ssh` client.\n\nPattern: *{ssh-client}*\n\nDefault: *ssh*\n\n### SSH settings\n\n`-ssh-command` *cmd*\n\nSet the command to execute when starting an ssh session.\nThe pattern *{host}* is replaced by the selected ssh entry.\n\nPattern: *{ssh-client}*\n\nDefault: *{terminal} -e {ssh-client} {host}*\n\n`-parse-hosts`\n\nParse the `/etc/hosts` file for entries.\n\nDefault: *disabled*\n\n`-[no-]parse-known-hosts`\n\nParse the `~/.ssh/known_hosts` file for entries.\n\nDefault: *enabled*\n\n### Run settings\n\n`-run-command` *cmd*\n\nSet command (*{cmd}*) to execute when running an application.\nSee *PATTERN*.\n\nDefault: *{cmd}*\n\nExample to run applications in a dedicated cgroup with systemd. Requires a\nshell to escape and interpolate the unit name correctly.\n\n```bash\n\"bash -c 'systemd-run --user --unit=app-rofi-\\$(systemd-escape {cmd})-\\$RANDOM {cmd}'\"\n```\n\n`-run-shell-command` *cmd*\n\nSet command to execute when running an application in a shell.\nSee *PATTERN*.\n\nDefault: *{terminal} -e {cmd}*\n\n`-run-list-command` *cmd*\n\nIf set, use an external tool to generate a list of executable commands. Uses\n`run-command`.\n\nDefault: *{cmd}*\n\n### Window switcher settings\n\n`-window-format` *format*\n\nFormat what is being displayed for windows.\n\n*format*: {field[:len]}\n\n*field*:\n\n- **w**: desktop name\n- **t**: title of window\n- **n**: name\n- **r**: role\n- **c**: class\n\n*len*: maximum field length (0 for auto-size). If length is negative, the entry\nwill be unchanged. If length is positive, the entry will be truncated or padded\nto fill that length.\n\ndefault: {w}  {c}   {t}\n\n`-window-command` *cmd*\n\nSet command to execute on selected window for an alt action (`-kb-accept-alt`).\nSee *PATTERN*.\n\nDefault: *\"wmctrl -i -R {window}\"*\n\n`-window-thumbnail`\n\nShow window thumbnail (if available) as icon in the window switcher.\n\nYou can stop rofi from exiting when closing a window (allowing multiple to be\nclosed in a row).\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n```\n\nYou can hide the currently active window with the 'hide-active-window' setting:\n\n```css\nconfiguration {\n  window {\n      hide-active-window: true;\n  }\n}\n```\n\nor pass `-window-hide-active-window true` on command line.\n\nYou can prefer the icon theme above the window set icon with the\n'prefer-icon-theme' setting:\n\n```css\nconfiguration {\n  window {\n      prefer-icon-theme: true;\n  }\n}\n```\n\nor pass `-window-prefer-icon-theme true` on command line.\n\n### Combi settings\n\n`-combi-modes` *mode1*,*mode2*\n\nThe modes to combine in combi mode.\nFor syntax to `-combi-modes`, see `-modes`.\nTo get one merge view, of `window`,`run`, and `ssh`:\n\n```bash\n    rofi -show combi -combi-modes \"window,run,ssh\" -modes combi\n```\n\n**NOTE**: The i3 window manager dislikes commas in the command when specifying\nan exec command. For that case, `#` can be used as a separator.\n\n`-combi-display-format`\n\nThe format string for entries in the `combi` dialog:\n\n- **mode**: the mode display name\n- **text**: the entry text\n\nPango markup can be used to formatting the output.\n\nDefault: {mode} {text}\n\nNote: This setting is ignored if `combi-hide-mode-prefix` is enabled.\n\n### History\n\n`-[no-]disable-history`\n\nDisable or re-enable history\n\n`-max-history-size` *number*\n\nMaximum number of entries to store in history. Defaults to 25. (WARNING: can\ncause slowdowns when set too high)\n\n### Message dialog\n\n`-e` *message*\n\nPops up a message dialog (used internally for showing errors) with *message*.\nMessage can be multi-line.\n\nPassing `-e -` reads (blocking) from standard in and displays this.\n\n### File browser settings\n\nFile browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n      /** Show hidden files. */\n      show-hidden: false;\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\nThese options can also be passed on the commandline, for example:\n\n```bash\nrofi -filebrowser-cancel-returns-1 true -show filebrowser\n```\n\nThe `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.\n\n### Recursive Browser settings\n\nRecursive file browser behavior can be controlled via the following options:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel-returns-1: true;\n      /** filter entries using regex */\n      filter-regex: \"(.*cache.*|.*\\.o)\";\n      /** command */\n      command: \"xdg-open\";\n   }\n}\n```\n\n### Entry history\n\nThe number of previous inputs for the entry box can be modified by setting\nmax-history on the entry box.\n\n```css\nconfiguration {\n    entry  {\n        max-history: 30;\n    }\n}\n```\n\nBy default the file is stored in the systems cache directory, in a file called\n`rofi-entry-history.txt`.\n\n### Other\n\n`-drun-use-desktop-cache`\n\nBuild and use a cache with the content of desktop files. Usable for systems\nwith slow hard drives.\n\n`-drun-reload-desktop-cache`\n\nIf `drun-use-desktop-cache` is enabled, rebuild a cache with the content of\ndesktop files.\n\n`-drun-url-launcher` *command*\n\nCommand to open a Desktop Entry that is a Link.\n\n`-pid` *path*\n\nMake **rofi** create a pid file and check this on startup. The pid file\nprevents multiple **rofi** instances from running simultaneously. This is\nuseful when running **rofi** from a key-binding daemon.\n\n`-replace`\n\nIf rofi is already running, based on pid file, try to kill that instance.\n\n`-display-{mode}` *string*\n\nSet the name to use for mode. This is used as prompt and in combi-browser.\n\nIt is now preferred to use the configuration file:\n\n```css\nconfiguration {\n  {mode} {\n    display-name: *string*;\n  }\n}\n```\n\n`-[no-]click-to-exit`\n\nClick the mouse outside the **rofi** window to exit.\n\nDefault: *enabled*\n\n`-global-kb`\n`-no-global-kb`\n\n(wayland) Override the compositor's keybindings, so that **rofi** can re-use them.\n\nDefault: *disabled*\n\n`-xserver-i300-workaround`\n\nWorkaround for bug in Xserver. See issue #611 and #1642 on the rofi issue\ntracker.\n\nDefault: *disabled*\n\n## PATTERN\n\nTo launch commands (for example, when using the ssh launcher), the user can\nenter the used command-line. The following keys can be used that will be\nreplaced at runtime:\n\n- `{host}`: the host to connect to\n- `{terminal}`: the configured terminal (see -terminal)\n- `{ssh-client}`: the configured ssh client (see -ssh-client)\n- `{cmd}`: the command to execute\n- `{window}`: the window ID of the selected window (in `window-command`)\n\nIt processes the string as follows: `{key}`\nis replaced by its value, if `{key}` is not set it is removed. If the `{key}`\nis in between `[]`  all the text between `[]` is removed if `{key}` is not set.\nOtherwise key is replaced and the `[]` are removed.\n\nFor example: `{ssh-client} [-p {port}] {host}`\n\n## THEMING\n\nPlease see **rofi-theme(5)** manpage for more information on theming.\n\n## KEY BINDINGS\n\nPlease see the **rofi-keys(5)** manpage for the keybindings and how to set them\nup.\n\nThe keybinding can also be used for actions, when the action is executed the\nmentioned keystroke is inserted:\n\n### Timeout\n\nYou can configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\n### Input change\n\nWhen the input of the textbox changes:\n\n```css\nconfiguration {\n  inputchange {\n      action: \"kb-row-first\";\n  }\n}\n```\n\n## Available Modes\n\n### window\n\nShow a list of all the windows and allow switching between them. Pressing the\n`delete-entry` binding (`shift-delete`) will close the window. Pressing the\n`accept-custom` binding (`control-enter` or `shift-enter`) will run a command\non the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### windowcd\n\nShows a list of the windows on the current desktop and allows switching between\nthem. Pressing the `delete-entry` binding (`shift-delete`) will kill the\nwindow. Pressing the `accept-custom` binding (`control-enter` or `shift-enter`)\nwill run a command on the window. (See option `window-command` );\n\nIf there is no match, it will try to launch the input.\n\n### run\n\nShows a list of executables in `$PATH` and can launch them (optional in a\nterminal).\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application with a file as the first argument.\n\n### drun\n\nSame as the **run** launches, but the list is created from the installed\ndesktop files. It automatically launches them in a terminal if specified in the\nDesktop File.\n\n- Pressing the `delete-entry` binding (`shift-delete`) will remove this entry\n    from the run history.\n\n- Pressing the `accept-custom` binding (`control-enter`) will run the command\n    as entered in the entry box.\n\n- Pressing the `accept-alt` binding (`shift-enter`) will run the command in a\n    terminal.\n\nWhen pressing the `mode-complete` binding (`Control-l`), you can use the File\nBrowser mode to launch the application passing a file as argument if specified\nin the desktop file.\n\nThe DRUN mode tries to follow the [XDG Desktop Entry\nSpecification](https://freedesktop.org/wiki/Specifications/desktop-entry-spec/)\nand should be compatible with applications using this standard.  Some\napplications create invalid desktop files, **rofi** will discard these entries.\nSee the debugging section for more info on DRUN mode, this will print why\ndesktop files are discarded.\n\nThere are a few advanced options to tweak the behaviour:\n\n```css\nconfiguration {\n   drun {\n      /** Scan the current users desktop for desktop files. */\n      scan-desktop: true;\n      /** Parse user desktop files. */\n      parse-user:   true;\n      /** Parse system desktop files. */\n      parse-system: false;\n      /** Disable DBusActivatable */\n      DBusActivatable: false;\n   }\n}\n```\n\n### ssh\n\nShows a list of SSH targets based on your `ssh` config file, and allows to\nquickly `ssh` into them.\n\n### keys\n\nShows a searchable list of key bindings.\n\n### script\n\nAllows custom scripted Modes to be added, see the **rofi-script(5)** manpage\nfor more information.\n\n### combi\n\nCombines multiple modes in one list. Specify which modes are included with the\n`-combi-modes` option.\n\nWhen using the combi mode, a *!bang* can be used to filter the results by modes.\nAll modes that match the bang as a prefix are included.\nFor example, say you have specified `-combi-modes run,window,windowcd`. If your\nquery begins with the bang `!w`, only results from the `window` and `windowcd`\nmodes are shown, even if the rest of the input text would match results from `run`.\n\nIf no match, the input is handled by the first combined modes.\n\n## FAQ\n\n### The text in the window switcher is not nicely aligned\n\nTry using a mono-space font or tabs + the tab-stops setting..\n\n### The window is completely black\n\nCheck quotes used on the command-line: you might have used `“` (\"smart quotes\")\ninstead of `\"` (\"machine quotes\").\n\n### What does the icon in the top right show?\n\nThe indicator shows:\n\n- `` Case insensitive and no sorting.\n- `-` Case sensitivity enabled, no sorting.\n- `+` Case insensitive and Sorting enabled\n- `±` Sorting and Case sensitivity enabled\"\n\n### Why do I see different icons for run,drun and window mode\n\nEach of these modes uses different methods of resolving the icon:\n\n- Window: It first uses the icon that the application exposes via the X11\n    Server, if none is set it does a lookup of the window Class name in the icon\n    theme.\n\n- drun: It uses the icon set in the desktop file.\n\n- run: It does a lookup using the executable name.\n\n## EXAMPLES\n\nSome basic usage examples of **rofi**:\n\nShow the run dialog:\n\n```bash\n    rofi -modes run -show run\n```\n\nShow the run dialog, and allow switching to Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes run,drun -show run\n```\n\nCombine the run and Desktop File run dialog (`drun`):\n\n```bash\n    rofi -modes combi -show combi -combi-modes run,drun\n```\n\nCombine the run and Desktop File run dialog (`drun`), and allow switching to\nwindow switcher:\n\n```bash\n    rofi -modes combi,window -show combi -combi-modes run,drun\n```\n\nPop up a text message claiming that this is the end:\n\n```bash\n    rofi -e \"This is the end\"\n```\n\nPop up a text message in red, bold font claiming that this is still the end:\n\n```bash\n    rofi -e \"<span color='red'><b>This is still the end</b></span>\" -markup\n```\n\nShow all key bindings:\n\n```bash\n    rofi -show keys\n```\n\n## i3\n\nIn [i3](http://i3wm.org/) you want to bind **rofi** to be launched on key\nrelease. Otherwise, it cannot grab the keyboard. See also the i3\n[manual](http://i3wm.org/docs/userguide.html):\n\nSome tools (such as `import` or `xdotool`) might be unable to run upon a\nKeyPress event, because the keyboard/pointer is still grabbed. For these\nsituations, the `--release` flag can be used, as it will execute the command\nafter the keys have been released.\n\n\n## Hyprland\n\nHyprland's animations make the launching of **Rofi** feel slower then needed.\nTo avoid this, add the following rule to your hyprland.conf file:\n\n```\nlayerrule = noanim,^(rofi)$\n```\nThis disables the animations on the **Rofi** window.\n\n## LICENSE\n\n```text\n    MIT/X11\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n\n## WEBSITE\n\n**rofi** website can be found [here](https://github.com/davatorium/rofi/)\n\n## SUPPORT\n\n**rofi** support can be obtained:\n\n- [GitHub Discussions](https://github.com/davatorium/rofi/discussions)\n- [IRC](irc://irc.libera.chat:6697/#rofi) (#rofi on irc.libera.chat),\n\n## DEBUGGING\n\nFor more information see **rofi-debugging(5)** manpage.\n\n## ISSUE TRACKER\n\nThe **rofi** issue tracker can be found [here](https://github.com/davatorium/rofi/issues)\nBefore creating an issue, consider posting a question on the [discussion forum](https://github.com/davatorium/rofi/discussions) first.\nWhen creating an issue, please read [this](https://github.com/davatorium/rofi/blob/master/.github/CONTRIBUTING.md)\nfirst.\n\n## SEE ALSO\n\n**rofi-sensible-terminal(1)**, **dmenu(1)**, **rofi-debugging(5)**,\n**rofi-theme(5)**, **rofi-script(5)**,\n**rofi-keys(5)**,**rofi-theme-selector(1)**,**rofi-dmenu(5)**\n\n## AUTHOR\n\n- Qball Cow <qball@blame.services>\n- Rasmus Steinke <rasi@xssn.at>\n- Morgane Glidic <sardemff7+rofi@sardemff7.net>\n\nOriginal code based on work by: [Sean Pringle](https://github.com/seanpringle/simpleswitcher) <sean.pringle@gmail.com>\n\nFor a full list of authors, check the `AUTHORS` file.\n"
  },
  {
    "path": "mkdocs/docs/downloads.md",
    "content": "# Downloads\n\n## Development\n\nFor development no tarball is released. Please follow the\n[Installation](../INSTALL/) instructions for obtaining and compiling\ndevelopment version.\n\n## [1.7.9](https://github.com/davatorium/rofi/releases/tag/1.7.9)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.9/rofi-1.7.9.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.9/rofi-1.7.9.tar.xz)\n\n## [1.7.8](https://github.com/davatorium/rofi/releases/tag/1.7.8)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.8/rofi-1.7.8.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.8/rofi-1.7.8.tar.xz)\n\n## [1.7.7](https://github.com/davatorium/rofi/releases/tag/1.7.7)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.7/rofi-1.7.7.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.7/rofi-1.7.7.tar.xz)\n\n## [1.7.6](https://github.com/davatorium/rofi/releases/tag/1.7.6)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.6/rofi-1.7.6.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.6/rofi-1.7.6.tar.xz)\n\n## [1.7.5](https://github.com/davatorium/rofi/releases/tag/1.7.5)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.5/rofi-1.7.5.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.5/rofi-1.7.5.tar.xz)\n\n## [1.7.4](https://github.com/davatorium/rofi/releases/tag/1.7.4)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.4/rofi-1.7.4.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.4/rofi-1.7.4.tar.xz)\n\n## [1.7.3](https://github.com/davatorium/rofi/releases/tag/1.7.3)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.3/rofi-1.7.3.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.3/rofi-1.7.3.tar.xz)\n\n## [1.7.2](https://github.com/davatorium/rofi/releases/tag/1.7.2)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.2/rofi-1.7.2.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.2/rofi-1.7.2.tar.xz)\n\n## [1.7.1](https://github.com/davatorium/rofi/releases/tag/1.7.1)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.1/rofi-1.7.1.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.1/rofi-1.7.1.tar.xz)\n\n## [1.7.0](https://github.com/davatorium/rofi/releases/tag/1.7.0)\n\n- [tar.gz](https://github.com/davatorium/rofi/releases/download/1.7.0/rofi-1.7.0.tar.gz)\n- [tar.xz](https://github.com/davatorium/rofi/releases/download/1.7.0/rofi-1.7.0.tar.xz)\n"
  },
  {
    "path": "mkdocs/docs/guides/DynamicThemes/dynamic_themes.md",
    "content": "# Dynamic Theme\n\nA new addition in rofi 1.7.5 that did not get a lot of attention is support for\nthe enabled keyword in the media statement and supporting environment values.\nOr more practical, you can modify your theme based on environment variables.\n\n```css\n\n@media ( enabled: env(DO_X, false)) {\n  listview {\n    orientation: vertical;\n  }\n}\n```\n\nYou can now enable this part of the theme by running rofi with `DO_X` set.\n\n```bash\nDO_X=true rofi -show combi\n```\n\n## Image browser example\n\nIn the current release, there is a\n[fullscreen_preview](https://github.com/davatorium/rofi/blob/next/themes/fullscreen-preview.rasi)\nas an example.\n\nIn this theme we are going to modify the filebrowser view with a preview widget\nthat we can enable.\n\nLets start with the basic theme.\n\n```css\n* {\n\tbackground-color: transparent;\n\ttext-color:       white;\n}\n\nwindow {\n\tfullscreen:       true;\n\tbackground-color: black/80%;\n\tpadding:          4em;\n\tchildren:         [ wrap, listview-split];\n\tspacing:          1em;\n}\n\n\n/** We add an extra child to this if PREVIEW=true */\nlistview-split {\n  orientation: horizontal;\n  spacing: 0.4em;\n  children: [listview];\n}\n\nwrap {\n\texpand: false;\n\torientation: vertical;\n\tchildren: [ inputbar, message ];\n\tbackground-image: linear-gradient(white/5%, white/40%);\n\tborder-color: lightblue;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n}\n\nicon-ib {\n\texpand: false;\n\tfilename: \"system-search\";\n\tvertical-align: 0.5;\n\thorizontal-align: 0.5;\n\tsize: 1em;\n}\ninputbar {\n\tspacing: 0.4em;\n\tpadding: 0.4em;\n\tchildren: [ icon-ib, entry ];\n}\nentry {\n\tplaceholder: \"Search\";\n\tplaceholder-color: grey;\n}\nmessage {\n\tbackground-color: red/20%;\n\tborder-color: lightsalmon;\n\tborder: 3px 0px 0px 0px;\n\tpadding: 0.4em;\n\tspacing: 0.4em;\n}\n\nlistview {\n\tflow: horizontal;\n\tfixed-columns: true;\n\tcolumns: 7;\n\tlines: 5;\n\tspacing: 1.0em;\n}\n\nelement {\n\torientation: vertical;\n\tpadding: 0.1em;\n\n\tbackground-image: linear-gradient(white/5%, white/20%);\n\tborder-color: lightblue /15%;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n\n  children: [element-icon, element-text ];\n}\nelement-icon {\n\tsize: calc(((100% - 8em) / 7 ));\n\thorizontal-align: 0.5;\n\tvertical-align: 0.5;\n}\nelement-text {\n\thorizontal-align: 0.5;\n\tvertical-align: 0.5;\n  padding: 0.2em;\n}\n\nelement selected {\n\tbackground-image: linear-gradient(white/25%, white/10%);\n\tborder-color: lightblue;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n}\n\n```\n\nWhen running this theme:\n```bash\nrofi -theme fullscreen-preview.rasi -show filebrowser\n```\n\n![Basic Theme](1.png)\n\nWe already prepared the place where we are going to add a 2nd widget.\nNow lets, at the end of the theme, add the extra element in a media block.\n\n```css\n@media ( enabled: env(PREVIEW, false)) {\n```\nThe variable is `PREVIEW`, if it is not set `false` is used.\nOtherwise the content of `PREVIEW` is parsed.\n\nThese will be merged into the theme on load:\n\n```css\n\n/**\n * Launching rofi with environment PREVIEW set to true\n * will split the screen and show a preview widget.\n */\n@media ( enabled: env(PREVIEW, false)) {\n  // preview widget\n  icon-current-entry {\n    expand:          true;\n    size:            80%;\n  }\n  // override the children of `listview-split`\n  listview-split {\n    children: [listview, icon-current-entry];\n  }\n  // Reduce to 4 columns\n  listview {\n    columns: 4;\n  }\n\n}\n```\n\nNow if we run it:\n\n```bash\nPREVIEW=true rofi -theme fullscreen-preview.rasi -show filebrowser\n```\n\nIt looks like this:\n\n![Image preview](2.png)\n\nWe can add more sections; for example for text only we hide the images:\n\n```css\n@media ( enabled: env(NO_IMAGE, false)) {\n\tlistview {\n\t\tcolumns: 1;\n\t\tspacing: 0.4em;\n\t}\n\telement {\n\t\tchildren: [ element-text ];\n\t}\n\telement-text {\n\t\thorizontal-align: 0.0;\n\t}\n}\n```\n\n## Wallpaper picker\n\nIf you run latest git version, you can now easily make a wallpaper picker:\n\n```bash\nPREVIEW=true rofi -theme fullscreen-preview.rasi -show filebrowser -filebrowser-command 'feh --bg-scale' -filebrowser-directory ~/Wallpapers/\n```\n"
  },
  {
    "path": "mkdocs/docs/guides/Plugins/2017-04-19-rofi-140-sneak-preview-plugins.md",
    "content": "> This guide is taken from the 1.4.0 release preview posts. The information\n> might be outdated, but in general should still be correct and a good starting\n> point for writing a plugin. Links have been updated. A recent plugin that can\n> be used as example can be found [here](https://git.sr.ht/~qball/rofi-ntfy).\n\n## Build system\n\n**Rofi** uses [autotools](https://en.wikipedia.org/wiki/GNU_build_system) as\nbuild system. While there are many opinions about the pre/cons off all the\ndifferent options out there (to many to go into in this blog post), we will\nstick to [autotools](https://en.wikipedia.org/wiki/GNU_build_system) for now.\n\nTo make life easier I create a template project\n[here](https://github.com/davatorium/rofi-plugin-template)\n\nThis includes the 2 files for the build system and the C template.\n\n### Configure.ac\n\nFirst we are going to update the `configure.ac` file:\n\n```text\nAC_INIT([rofi-plugin-template], [0.0.1],\n[https://my-neat-plugin.org//],[],[https://support.my-neat-plugin.org/])\n\nAC_CONFIG_HEADER([config.h])\n\nAC_CONFIG_MACRO_DIRS([m4])\nAM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects dist-xz])\nAM_SILENT_RULES([yes])\n\nAC_PROG_CC([clang gcc cc])\nAC_PROG_CC_C99\nAM_PROG_CC_C_O\n\nAC_USE_SYSTEM_EXTENSIONS\n\nAM_PROG_AR\n\nAM_CFLAGS=\"-Wall -Wextra -Wparentheses -Winline -pedantic  -Wunreachable-code\"\n\nPKG_PROG_PKG_CONFIG\n\nPKG_CHECK_MODULES([glib],     [glib-2.0 >= 2.40 gio-unix-2.0 gmodule-2.0 ])\nPKG_CHECK_MODULES([rofi],     [rofi])\n\n[rofi_PLUGIN_INSTALL_DIR]=\"`$PKG_CONFIG --variable=pluginsdir rofi`\"\nAC_SUBST([rofi_PLUGIN_INSTALL_DIR])\n\nLT_INIT([disable-static])\n\nAC_SUBST([AM_CFLAGS])\n\n\nAC_CONFIG_FILES([Makefile ])\nAC_OUTPUT\n```\n\nBasically the only thing here we need to change is the name of the plugin, the\nwebsite and the support site.\n\n```diff\nAC_INIT([rofi-file-browser], [0.0.1], [https://davedavenport.github.io/rofi/],[],[https://reddit.org/r/qtools/])\n```\n\n### Makefile.am\n\nWe need to make a similar change in the `Makefile.am` file, this is important so\neach plugin has a unique name. (if they are all called myplugin, it would be\nhard to install more then one plugin.)\n\n```text\nACLOCAL_AMFLAGS=-I m4\nplugindir=@rofi_PLUGIN_INSTALL_DIR@\n\nplugin_LTLIBRARIES = myplugin.la\n\nmyplugin_la_SOURCES=\\\n\t\t src/myplugin.c\n\nmyplugin_la_CFLAGS= @glib_CFLAGS@ @rofi_CFLAGS@\nmyplugin_la_LIBADD= @glib_LIBS@ @rofi_LIBS@\nmyplugin_la_LDFLAGS= -module -avoid-version\n```\n\nSo we do a search and replace from `myplugin` to `file_browser`:\n\n```text\nACLOCAL_AMFLAGS=-I m4\nplugindir=${libdir}/rofi/\n\nplugin_LTLIBRARIES = file_browser.la\n\nfile_browser_la_SOURCES=\\\n\t\t src/file_browser.c\n\nfile_browser_la_CFLAGS= @glib_CFLAGS@ @rofi_CFLAGS@\nfile_browser_la_LIBADD= @glib_LIBS@ @rofi_LIBS@\nfile_browser_la_LDFLAGS= -module -avoid-version\n```\n\nAs you noticed I also changed the name of the c template file. This is not\nneeded.\n\n## Building the system\n\nNow that we have this setup, it is easy to build:\n\n- Generate the build system:\n\n```bash\nautoreconf -i\n```\n\n- Create a `build` directory.\n\n```bash\nmkdir build\ncd build\n```\n\n- Run `configure` \n\n```bash\n../configure\n```\n\n- build\n\n```bash\nmake\n```\n- install\n\n```bash\nmake install\n```\n\nYou can now test the plugin by calling:\n\n```bash\nrofi -show myplugin -modi myplugin\n```\n\nIf we start changing the template, the name to use will change.\n\n## Edit the C template\n\nThe first thing todo is personalize the template. Below I have modified it so\nit is called file-browser:\n\n```c\n/**\n * rofi-file-browser\n *\n * MIT/X11 License\n * Copyright (c) 2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <string.h>\n#include <errno.h>\n#include <gmodule.h>\n\n#include <rofi/mode.h>\n#include <rofi/helper.h>\n#include <rofi/mode-private.h>\n\n#include <stdint.h>\n\nG_MODULE_EXPORT Mode mode;\n\n/**\n * The internal data structure holding the private data of the TEST Mode.\n */\ntypedef struct\n{\n    char **array;\n    unsigned int array_length;\n} FileBrowserModePrivateData;\n\n\nstatic void get_file_browser (  Mode *sw )\n{\n    /**\n     * Get the entries to display.\n     * this gets called on plugin initialization.\n     */\n}\n\n\nstatic int file_browser_mode_init ( Mode *sw )\n{\n    /**\n     * Called on startup when enabled (in modi list)\n     */\n    if ( mode_get_private_data ( sw ) == NULL ) {\n        FileBrowserModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) );\n        mode_set_private_data ( sw, (void *) pd );\n        // Load content.\n        get_file_browser ( sw );\n    }\n    return TRUE;\n}\nstatic unsigned int file_browser_mode_get_num_entries ( const Mode *sw )\n{\n    const FileBrowserModePrivateData *pd = (const FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    return pd->array_length;\n}\n\nstatic ModeMode file_browser_mode_result ( Mode *sw, int mretv, char **input, unsigned int selected_line )\n{\n    ModeMode           retv  = MODE_EXIT;\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    if ( mretv & MENU_NEXT ) {\n        retv = NEXT_DIALOG;\n    } else if ( mretv & MENU_PREVIOUS ) {\n        retv = PREVIOUS_DIALOG;\n    } else if ( mretv & MENU_QUICK_SWITCH ) {\n        retv = ( mretv & MENU_LOWER_MASK );\n    } else if ( ( mretv & MENU_OK ) ) {\n        retv = RELOAD_DIALOG;\n    } else if ( ( mretv & MENU_ENTRY_DELETE ) == MENU_ENTRY_DELETE ) {\n        retv = RELOAD_DIALOG;\n    }\n    return retv;\n}\n\nstatic void file_browser_mode_destroy ( Mode *sw )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    if ( pd != NULL ) {\n        g_free ( pd );\n        mode_set_private_data ( sw, NULL );\n    }\n}\n\nstatic char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    // Only return the string if requested, otherwise only set state.\n    return get_entry ? g_strdup(\"n/a\"): NULL;\n}\n\nstatic int file_browser_token_match ( const Mode *sw, GRegex **tokens, unsigned int index )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    // Call default matching function.\n    return helper_token_match ( tokens, pd->array[index]);\n}\n\nMode mode =\n{\n    .abi_version        = ABI_VERSION,\n    .name               = \"file_browser\",\n    .cfg_name_key       = \"display-file_browser\",\n    ._init              = file_browser_mode_init,\n    ._get_num_entries   = file_browser_mode_get_num_entries,\n    ._result            = file_browser_mode_result,\n    ._destroy           = file_browser_mode_destroy,\n    ._token_match       = file_browser_token_match,\n    ._get_display_value = _get_display_value,\n    ._get_message       = NULL,\n    ._get_completion    = NULL,\n    ._preprocess_input  = NULL,\n    .private_data       = NULL,\n    .free               = NULL,\n};\n```\n\nIf we now rebuild the plugin, we need to run the following command:\n\n```bash\nrofi -show file_browser -modi file_browser\n```\n### The mode description \n\nThe mode is defined by the `Mode` structure, every mode in rofi has one of the\nplugins.\n\n```c\nMode mode =\n{\n    .abi_version        = ABI_VERSION,\n    .name               = \"file_browser\",\n    .cfg_name_key       = \"display-file_browser\",\n    ._init              = file_browser_mode_init,\n    ._get_num_entries   = file_browser_mode_get_num_entries,\n    ._result            = file_browser_mode_result,\n    ._destroy           = file_browser_mode_destroy,\n    ._token_match       = file_browser_token_match,\n    ._get_display_value = _get_display_value,\n    ._get_message       = NULL,\n    ._get_completion    = NULL,\n    ._preprocess_input  = NULL,\n    .private_data       = NULL,\n    .free               = NULL,\n};\n```\n\nThe ABI_VERSION is defined in **rofi** header file, so that **rofi** can detect\nwhat ABI the plugin was compiled against. Not every function needs to be\nimplemented, in the plugin we show the minimum set.\n\nLets modify each of the above functions to implement something useful.\n\n### FileBrowserModePrivateData\n\nThis is a structure that holds all the private data of this mode.\nWe are going to extend this so it can hold the state of information we want to\nview.\n\nWe want to differentiate between 3 different rows:\n\n- Go one level up\n- Directory\n- Regular file\n\nSo we add an enum:\n\n```c\nenum FBFileType {                                                         \n    UP,                                                                   \n    DIRECTORY,                                                            \n    RFILE,                                                                \n};                                                                        \n```\n\nWe need a structure that hold each entry.\n\n-   It should have a **name** we are going to show the user. This will hold an\n    `utf-8` string. (rofi will only display utf-8). \n\n-   It should hold the **path** to the entry. This will be in the file-systems\n    encoding.\n\n-   The type it holds.\n\n```c\ntypedef struct {                                                          \n    char *name;                                                           \n    char *path;                                                           \n    enum FBFileType type;                                                 \n} FBFile;                                                                 \n```\n\nThen in the *private* data we hold all the relevant information. \n\n- The current directory to show.\n- Array of all the *FBFile* we want to show.\n- The length of the array.\n\n```c                                                                          \ntypedef struct                                                            \n{                                                                         \n    GFile *current_dir;                                                   \n    FBFile *array;                                                        \n    unsigned int array_length;                                            \n} FileBrowserModePrivateData;                                             \n```\n\n###  Initialization\n\nNow that we have the data structure to hold our information, we need to\ninitialize it and fill it.\n\n```c\nstatic int file_browser_mode_init ( Mode *sw )                        \n{                                                                     \n    if ( mode_get_private_data ( sw ) == NULL ) {                     \n        FileBrowserModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) );\n        mode_set_private_data ( sw, (void *) pd );                    \n        pd->current_dir = g_file_new_for_path(g_get_home_dir () );    \n        get_file_browser ( sw );                                      \n    }                                                                 \n    return TRUE;                                                      \n}                                                                     \n```\n\nThe function first checked if we already initialized the private data. You can\ninclude a mode multiple times, and we normally don't want it initialized\nmultiple times.\n\nWe then create a, zero initialized,  `FileBrowserModePrivateData` structure and\nset this on the mode. Set the current directory to the users home directory and\ncall `get_file_browser` that will load in the entries. We will discuss this one\nlater.\n\n### Destroying\n\nOn shutdown we want to cleanup, so there is also a destroy function.\n\n```c\nstatic void file_browser_mode_destroy ( Mode *sw )                                              \n{                                                                                               \n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    if ( pd != NULL ) {                                                                         \n        g_object_unref ( pd->current_dir );                                                     \n        free_list ( pd );                                                                       \n        g_free ( pd );                                                                          \n        mode_set_private_data ( sw, NULL );                                                     \n    }                                                                                           \n}                                                                                               \n```\n\nThis does the exact opposite.\n\nFor completeness:\n\n```c\nstatic void free_list ( FileBrowserModePrivateData *pd )\n{\n    for ( unsigned int i = 0; i < pd->array_length; i++ ) {\n        FBFile *fb = & ( pd->array[i] );\n        g_free ( fb->name );\n        g_free ( fb->path );\n    }\n    g_free (pd->array);\n    pd->array  = NULL;\n    pd->array_length = 0;\n}\n```\n\n### Loading the entries\n\nLets dive deeper into the `get_file_browser` function.\n\n```c\nstatic void get_file_browser (  Mode *sw )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n```\nWe want to get access to the private data structure.\n\n```c\n    char *cdir = g_file_get_path ( pd->current_dir );\n    DIR *dir = opendir ( cdir );\n    if ( dir ) {\n        struct dirent *rd = NULL;\n        while ((rd = readdir (dir)) != NULL )\n        {\n```\n\nWe open the directory and we iterate over each entry. We then want to skip over\nhidden files (starting with a .) and insert a special up node for going up one\ndirectory.  For this  we do not need a path, and we show \"..\" to the user.\n\n```c \n            if ( g_strcmp0 ( rd->d_name, \"..\" ) == 0 ){\n                    pd->array = g_realloc ( pd->array, (pd->array_length+1)*sizeof(FBFile));\n                    pd->array[pd->array_length].name = g_strdup ( \"..\" );\n                    pd->array[pd->array_length].path = NULL;\n                    pd->array[pd->array_length].type = UP;\n                    pd->array_length++;\n                    continue;\n\n            } else if ( rd->d_name[0] == '.' ) {\n                continue;\n            }\n```\n\nWe do a similar filtering act for the rest of the files, we skip `fifo`, `blk`,`character` and `socket` files.\n\n```c\n            switch ( rd->d_type )\n            {\n                case DT_BLK:\n                case DT_CHR:\n                case DT_FIFO:\n                case DT_UNKNOWN:\n                case DT_SOCK:\n                    break;\n                case DT_REG:\n                case DT_DIR:\n                    pd->array = g_realloc ( pd->array, (pd->array_length+1)*sizeof(FBFile));\n                    pd->array[pd->array_length].name = g_strdup ( rd->d_name );\n                    pd->array[pd->array_length].path = g_build_filename ( pd->current_dir, rd->d_name, NULL );\n                    pd->array[pd->array_length].type = (rd->d_type == DT_DIR)? DIRECTORY: RFILE;\n                    pd->array_length++; \n            }\n        }\n        closedir ( dir );\n    }\n```\n\nWe then sort the list in a way the user expects this.\n\n```c\n    g_qsort_with_data ( pd->array, pd->array_length, sizeof (FBFile ), compare, NULL );\n}\n```\n\nQsort here uses the following sort function:\n\n```c\nstatic gint compare ( gconstpointer a, gconstpointer b, gpointer data )\n{\n    FBFile *fa = (FBFile*)a;\n    FBFile *fb = (FBFile*)b;\n    if ( fa->type != fb->type ){\n        return (fa->type - fb->type);\n    }\n\n    return g_strcmp0 ( fa->name, fb->name );\n}\n```\n\n## Showing the entries\n\nWhen showing each entry, rofi calls the `_get_display_value` function.  It calls\nthem in two situations, to get the state and the display string. Or just to get\nthe new state. If you need to return a string (should always be malloced), the\n`get_entry` parameter is set to 1.\n\nWe currently show the name, and prepend an icon using the Awesome Font.\n\n```c\nstatic char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n\n    // Only return the string if requested, otherwise only set state.\n    if ( !get_entry ) return NULL;\n    if ( pd->array[selected_line].type == DIRECTORY ){\n        return g_strdup_printf ( \" %s\", pd->array[selected_line].name);\n    } else if ( pd->array[selected_line].type == UP ){\n        return g_strdup( \" ..\");\n    } else {\n        return g_strdup_printf ( \" %s\", pd->array[selected_line].name);\n    }\n    return g_strdup(\"n/a\"); \n}\n```\n\nThe `selected_line` setting will always be within range 0 and the result of\n`.get_num_entries`.\n\n```c\nstatic unsigned int file_browser_mode_get_num_entries ( const Mode *sw )\n{\n    const FileBrowserModePrivateData *pd = (const FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    return pd->array_length;\n}\n```\n\n> The `attr_list` argument is there for more advanced markup of the string.\n\n## Filtering the entries\n\nWhen filtering we want to filter on the file name, we luckily store this entry\nin `FBFile::name`. To use **rofi**'s matching algorithm we can use the\n`helper_token_match` function.\n\n```c\nstatic int file_browser_token_match ( const Mode *sw, GRegex **tokens, unsigned int index )\n{\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n\n    // Call default matching function.\n    return helper_token_match ( tokens, pd->array[index].name);\n}\n```\n\nThe `index` setting will always be within range 0 and the result of\n`.get_num_entries`.\n\n## Running it\n\nNow we should be able to build it, install it and run it and see the result.\n\n```bash\nrofi -show file_browser -modi file_browser\n```\n\n![rofi file browser](rofi-file-browser.png)\n\n## Handling selected entries \n\nThis is just an example and can probably be implemented nicer.\nHere it also shows some rudimentary parts in **rofi**, that show some of the\nugly details, that will be cleaned up in the future.\n\n```c\n\nstatic ModeMode file_browser_mode_result ( Mode *sw, int mretv, char **input, unsigned int selected_line )\n{\n    ModeMode           retv  = MODE_EXIT;\n    FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *) mode_get_private_data ( sw );\n    if ( mretv & MENU_NEXT ) {\n        retv = NEXT_DIALOG;\n    } else if ( mretv & MENU_PREVIOUS ) {\n        retv = PREVIOUS_DIALOG;\n    } else if ( mretv & MENU_QUICK_SWITCH ) {\n        retv = ( mretv & MENU_LOWER_MASK );\n```\n\nThis is the user pressing `enter` on the entry. We handle it differently for\neach type.\n\n```c\n    } else if ( ( mretv & MENU_OK ) ) {\n        if ( selected_line < pd->array_length )\n        {\n            if ( pd->array[selected_line].type == UP ) {\n                GFile *new = g_file_get_parent ( pd->current_dir );\n               if ( new ){\n                   g_object_unref ( pd->current_dir );\n                   pd->current_dir = new;\n                   free_list (pd);\n                   get_file_browser ( sw );\n                   return RESET_DIALOG;\n               }\n            } else if ( pd->array[selected_line].type == DIRECTORY ) {\n                GFile *new = g_file_new_for_path ( pd->array[selected_line].path );\n                g_object_unref ( pd->current_dir );\n                pd->current_dir = new;\n                free_list (pd);\n                get_file_browser ( sw );\n                return RESET_DIALOG;\n            } else if ( pd->array[selected_line].type == RFILE ) {\n                char *d = g_strescape ( pd->array[selected_line].path,NULL );\n                char *cmd = g_strdup_printf(\"xdg-open '%s'\", d );\n                g_free(d);\n                char *cdir = g_file_get_path ( pd->current_dir );\n                helper_execute_command ( cdir,cmd, FALSE );\n                g_free ( cdir );\n                g_free ( cmd );\n                return MODE_EXIT;\n            }\n        }\n        retv = RELOAD_DIALOG;\n```\n\nHandle custom entry that does not match an entry:\n\n```c\n    } else if ( (mretv&MENU_CUSTOM_INPUT) && *input ) {\n        char *p = rofi_expand_path ( *input );\n        char *dir = g_filename_from_utf8 ( p, -1, NULL, NULL, NULL );\n        g_free (p);\n        if ( g_file_test ( dir, G_FILE_TEST_EXISTS )  )\n        {\n            if ( g_file_test ( dir, G_FILE_TEST_IS_DIR ) ){\n                g_object_unref ( pd->current_dir );\n                pd->current_dir = g_file_new_for_path ( dir );\n                g_free ( dir );\n                free_list (pd);\n                get_file_browser ( sw );\n                return RESET_DIALOG;\n            }\n\n        }\n        g_free ( dir );\n        retv = RELOAD_DIALOG;\n```\n\nWe do not support `delete`, just reload.\n```c\n    } else if ( ( mretv & MENU_ENTRY_DELETE ) == MENU_ENTRY_DELETE ) {\n        retv = RELOAD_DIALOG;\n    }\n    return retv;\n}\n```\n\nThe `RESET_DIALOG` will clear the input bar and reload the view, `RELOAD_DIALOG`\nwill reload the view and re-filter based on the current text. \n\n> Note: `rofi_expand_path` will expand `~` and `~me/` into it full absolute\n> path. Note: `helper_execute_command` will spawn command. \n"
  },
  {
    "path": "mkdocs/docs/guides/Positioning/theme3-positioning.markdown",
    "content": "# Positioning Rofi on the monitor\n\nIn the current theme format you set these properties on the `window`  widget.\n\nThe first, location, determines where **rofi** is placed on the monitor, the\nsecond what point of the **rofi** window connects there. This sounds\ncomplicated, but it ain't.\n\n## location setting\n\nThe location setting determines the place of the window on the monitor.\n\nThe location setting supports the following values:\n\n- north\n- northeast\n- northwest\n- south\n- southeast\n- southwest\n- east\n- west\n- center\n\nThis is depicted in the diagram below:\n\n![location](anchors.svg)\n\n## anchor setting\n\nThe anchor sets what point of the **rofi** window is placed at the specified\n*location*.\n\nThe *anchor* settings supports the same values as the *location* setting.\n\nIf you want the middle of the **rofi** window to be always located at the\ncenter of the monitor set both *location* and *anchor* to `center`.\n\nIf the **rofi** window resizes, its center will stay at the center. If you set\nthe *anchor* to `north` the top of the **rofi** window is at the center of the\nmonitor, and the window will grow down.\n\nIf you set the *anchor* and *location* to `south`, **rofi** is located at the\nbottom center and the window grows up.\n\n> Note that if you set the *anchor* to `south`  and the *location* to `north`\n> the **rofi** window will be placed above the monitor and might not be\n> visible.\n\n> In another blog post we will explain how the dynamic sizing behaviour of\n> **rofi** can be tweaked or disabled.\n\nSo the following theme setting will place the top of the **rofi** window in the\ncenter of the monitor:\n\n```css\nwindow {\n    location: center;\n    anchor: north;\n}\n```\n\nAs depicted here, RED is the location (center of screen), GREEN is the anchor\non **rofi** window (north):\n\n![positions](example-pos.png)\n\n> Quick hint, if you want to quickly test out changes to the theme, without\n> editing the file, run **rofi** like:\n\n```bash\nrofi -show run -theme-str \"window { location: center; anchor: north;}\"\n```\n"
  },
  {
    "path": "mkdocs/docs/guides/Transparency/theme3-transparency.markdown",
    "content": "## Transparency within rofi\n\n> The images in this guide are outdated, but the principals still hold.\n\n**Rofi** window is build up by first drawing the background, and then each\nwidget above it, with the correct transparency factor.\n\nRemember the general widget structure:\n\n![structure](structure.svg)\n\nThis means if you set every widget to be 30% transparent on a white background:\nit will look like: \n\n![images](rofi-transp.png)\n\nThe transparency applies one on top of the other, so while they all are 30%, in\nthe end it will be less transparent.\n\n> Try it yourself\n\n```bash\nrofi -theme-str '@theme \"/dev/null\"  window { background-color: white; }* { padding:5; background-color: rgba(20,20,20,0.5);}' -show run\n```\n\nThis can sometimes be difficult when creating themes with a nice transparent\nbackground.\nThe trick to make this work nicely is the following.\n\nSpecify fully transparent background on the highest level.\n\n```css\n* {\n    background:  transparent;\n}\n```\n\nThen set the background on the window box.\n\n```css\nwindow {\n    background: #cc1c1c1c;\n}\n```\n\nNow if you only set the background on widgets you want differently colored, it\nnicely works out.\n\n## Transparency on the window\n\nThis determines how transparency on the window is handled.\nThis is set the be `transparency` option on the `window` widget.\nThe option takes a string. There are basically 4 options:\n\n### No transparency or \"real\"\n\nThe background of the window is black and fully transparent, and everything is\ndrawn on top of this. This means that if you have a composite manager (ARGB\nwindow), you get a fully transparent background, otherwise fully black. \n\nThis is the preferred option if you have a composite manager running.\n\n![rofi real](rofi-real.png)\n\nThis image is actually partially transparent (won't show here clearly as block\nbackground is white.)\n\n### Fake transparency or \"screenshot\"\n\nThis tries to emulate a transparent window by taking a screenshot of the window\nbefore showing and then drawing everything on top of this. While this is not an\nideal solution (it won't update if something changes in the background) it is\noften a very usable facsimile.\n\n![rofi fake](rofi-fake.png)\n\n> Note: It can get very slow, especially on high resolution (4k) monitors.\n\n### Background transparency or \"background\"\n\nThis uses the background image (the root window image). This is, in my opinion,\nmostly useful when used fullscreen.\n\n![rofi background](rofi-background2.png)\n\n![rofi background2](rofi-background.png)\n\n### Picture\n\nIf instead of one of the above option, you specify a path to a png file this is\nused as background image. This can create a theme where you use paper as\nbackground.\n\n![rofi paper](rofi-paper.png)\n"
  },
  {
    "path": "mkdocs/docs/index.md",
    "content": "![rofi](images/rofi-logo-full.png)\n\n# Welcome to Rofi Documentation\n\nThis website holds the web-version of the manpages for rofi and several guides\nthat have been published over the past years.\nThe manpages are grouped on rofi version.\n\n- [Downloads](downloads.md)\n- [Installation](INSTALL.md)\n- [Themes](themes/themes.md)\n- [User scripts (wiki)](https://github.com/davatorium/rofi/wiki/User-scripts)\n\n## Development version\n\n- [Rofi manpage](current/rofi.1.markdown)\n- [Themes](current/rofi-theme.5.markdown)\n- [Dmenu](current/rofi-dmenu.5.markdown)\n- [Script](current/rofi-script.5.markdown)\n- [Debugging](current/rofi-debugging.5.markdown)\n- [Keys](current/rofi-keys.5.markdown)\n- [Actions](current/rofi-actions.5.markdown)\n- [Thumbnails](current/rofi-thumbnails.5.markdown)\n\n## Stable\n\n- [Rofi manpage](2.0.0/rofi.1.markdown)\n- [Themes](2.0.0/rofi-theme.5.markdown)\n- [Dmenu](2.0.0/rofi-dmenu.5.markdown)\n- [Script](2.0.0/rofi-script.5.markdown)\n- [Debugging](2.0.0/rofi-debugging.5.markdown)\n- [Keys](2.0.0/rofi-keys.5.markdown)\n- [Thumbnails](2.0.0/rofi-thumbnails.5.markdown)\n- [Actions](2.0.0/rofi-actions.5.markdown)\n\n## Guides\n\n- [Transparency](guides/Transparency/theme3-transparency)\n- [Positioning](guides/Positioning/theme3-positioning)\n- [Plugins](guides/Plugins/2017-04-19-rofi-140-sneak-preview-plugins.md)\n- [Dynamic Theme](guides/DynamicThemes/dynamic_themes.md)\n"
  },
  {
    "path": "mkdocs/docs/themes/capture.sh",
    "content": "#!/usr/bin/env bash\n\nTHEMES=../../../themes/*.rasi\nROFI_BIN=../../../build/rofi\n\nfunction generate_options() {\n\techo -en \"rofi\\0icon\\x1frofi\\n\"\n\techo -en \"help browser\\0icon\\x1fhelp-browser\\n\"\n\techo -en \"thunderbird\\0icon\\x1fthunderbird\\n\"\n\techo -en \"Urgent\\0icon\\x1femblem-urgent\\n\"\n\techo -en \"Active\\0icon\\x1fface-wink\\n\"\n\techo -en \"folder\\0icon\\x1ffolder\\n\"\n\techo -en \"Icon font 🐢 🥳\\n\"\n\techo -en \"Font icon\\0icon\\x1f<span size='x-large' color='red'>:-)</span>\\n\"\n\techo -en \"Quit\\0icon\\x1fapplication-exit\\n\"\n}\n\nfunction run_theme {\n\ttheme=$1\n\tBASE=\"$(basename ${theme})\"\n\tNAME=${BASE%.rasi}\n\texport ROFI_PNG_OUTPUT=\"${NAME}.png\"\n\tif [ \"${NAME}\" = \"default\" ]; then\n\t\techo \"# Default theme\" >>themes.md\n\telse\n\t\techo \"# [${NAME}](https://github.com/davatorium/rofi/blob/next/themes/${BASE})\" >>themes.md\n\tfi\n\techo \"\" >>themes.md\n\tgenerate_options | ${ROFI_BIN} -theme-str \"@theme \\\"${theme}\\\"\" \\\n\t\t-no-config -dmenu -p \"mode\" -show-icons \\\n\t\t-u 3 -a 4 -mesg \"Message box for extra information\" \\\n\t\t-take-screenshot-quit 1500\n\n\techo \"![${NAME}](${NAME}.png)\" >>themes.md\n\techo \"\" >>themes.md\n}\n\necho \"# Included Themes\" >themes.md\n\necho \"Below is a list of themes shipped with rofi.\" >>themes.md\necho \"Use \\`rofi-theme-selector\\` to select and use one of these themes.\" >>themes.md\n\nXvfb :1234 -screen 0 1920x1080x24 &\nXEPHYR_PID=$!\nexport DISPLAY=:1234\nsleep 0.5\nrun_theme \"default\"\nfor theme in ${THEMES}; do\n\trun_theme \"${theme}\"\ndone\nkill ${XEPHYR_PID}\n"
  },
  {
    "path": "mkdocs/docs/themes/themes.md",
    "content": "# Included Themes\nBelow is a list of themes shipped with rofi.\nUse `rofi-theme-selector` to select and use one of these themes.\n# Default theme\n\n![default](default.png)\n\n# [Adapta-Nokto](https://github.com/davatorium/rofi/blob/next/themes/Adapta-Nokto.rasi)\n\n![Adapta-Nokto](Adapta-Nokto.png)\n\n# [android_notification](https://github.com/davatorium/rofi/blob/next/themes/android_notification.rasi)\n\n![android_notification](android_notification.png)\n\n# [Arc-Dark](https://github.com/davatorium/rofi/blob/next/themes/Arc-Dark.rasi)\n\n![Arc-Dark](Arc-Dark.png)\n\n# [Arc](https://github.com/davatorium/rofi/blob/next/themes/Arc.rasi)\n\n![Arc](Arc.png)\n\n# [arthur](https://github.com/davatorium/rofi/blob/next/themes/arthur.rasi)\n\n![arthur](arthur.png)\n\n# [blue](https://github.com/davatorium/rofi/blob/next/themes/blue.rasi)\n\n![blue](blue.png)\n\n# [c64](https://github.com/davatorium/rofi/blob/next/themes/c64.rasi)\n\n![c64](c64.png)\n\n# [DarkBlue](https://github.com/davatorium/rofi/blob/next/themes/DarkBlue.rasi)\n\n![DarkBlue](DarkBlue.png)\n\n# [dmenu](https://github.com/davatorium/rofi/blob/next/themes/dmenu.rasi)\n\n![dmenu](dmenu.png)\n\n# [docu](https://github.com/davatorium/rofi/blob/next/themes/docu.rasi)\n\n![docu](docu.png)\n\n# [fancy2](https://github.com/davatorium/rofi/blob/next/themes/fancy2.rasi)\n\n![fancy2](fancy2.png)\n\n# [fancy](https://github.com/davatorium/rofi/blob/next/themes/fancy.rasi)\n\n![fancy](fancy.png)\n\n# [fullscreen-preview](https://github.com/davatorium/rofi/blob/next/themes/fullscreen-preview.rasi)\n\n![fullscreen-preview](fullscreen-preview.png)\n\n# [glue_pro_blue](https://github.com/davatorium/rofi/blob/next/themes/glue_pro_blue.rasi)\n\n![glue_pro_blue](glue_pro_blue.png)\n\n# [gruvbox-dark-hard](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-dark-hard.rasi)\n\n![gruvbox-dark-hard](gruvbox-dark-hard.png)\n\n# [gruvbox-dark](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-dark.rasi)\n\n![gruvbox-dark](gruvbox-dark.png)\n\n# [gruvbox-dark-soft](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-dark-soft.rasi)\n\n![gruvbox-dark-soft](gruvbox-dark-soft.png)\n\n# [gruvbox-light-hard](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-light-hard.rasi)\n\n![gruvbox-light-hard](gruvbox-light-hard.png)\n\n# [gruvbox-light](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-light.rasi)\n\n![gruvbox-light](gruvbox-light.png)\n\n# [gruvbox-light-soft](https://github.com/davatorium/rofi/blob/next/themes/gruvbox-light-soft.rasi)\n\n![gruvbox-light-soft](gruvbox-light-soft.png)\n\n# [iggy](https://github.com/davatorium/rofi/blob/next/themes/iggy.rasi)\n\n![iggy](iggy.png)\n\n# [Indego](https://github.com/davatorium/rofi/blob/next/themes/Indego.rasi)\n\n![Indego](Indego.png)\n\n# [lb](https://github.com/davatorium/rofi/blob/next/themes/lb.rasi)\n\n![lb](lb.png)\n\n# [material](https://github.com/davatorium/rofi/blob/next/themes/material.rasi)\n\n![material](material.png)\n\n# [Monokai](https://github.com/davatorium/rofi/blob/next/themes/Monokai.rasi)\n\n![Monokai](Monokai.png)\n\n# [paper-float](https://github.com/davatorium/rofi/blob/next/themes/paper-float.rasi)\n\n![paper-float](paper-float.png)\n\n# [Paper](https://github.com/davatorium/rofi/blob/next/themes/Paper.rasi)\n\n![Paper](Paper.png)\n\n# [purple](https://github.com/davatorium/rofi/blob/next/themes/purple.rasi)\n\n![purple](purple.png)\n\n# [sidebar](https://github.com/davatorium/rofi/blob/next/themes/sidebar.rasi)\n\n![sidebar](sidebar.png)\n\n# [sidebar-v2](https://github.com/davatorium/rofi/blob/next/themes/sidebar-v2.rasi)\n\n![sidebar-v2](sidebar-v2.png)\n\n# [solarized_alternate](https://github.com/davatorium/rofi/blob/next/themes/solarized_alternate.rasi)\n\n![solarized_alternate](solarized_alternate.png)\n\n# [solarized](https://github.com/davatorium/rofi/blob/next/themes/solarized.rasi)\n\n![solarized](solarized.png)\n\n"
  },
  {
    "path": "mkdocs/mkdocs.yml",
    "content": "site_name: Rofi Documentation\nrepo_url: https://github.com/davatorium/rofi/\nedit_uri: mkdocs/docs/\ntheme: readthedocs\nnav:\n  - License: COPYING.md\n  - Issue Tracker: https://github.com/davatorium/rofi/issues\n  - Discussions Forum: https://github.com/davatorium/rofi/discussions\n  - Downloads: downloads.md\n  - Installation: INSTALL.md\n  - Configuration: CONFIG.md\n  - Themes: themes/themes.md\n  - Guides:\n    - Transparency: guides/Transparency/theme3-transparency.markdown\n    - Positioning: guides/Positioning/theme3-positioning.markdown\n    - Plugins: guides/Plugins/2017-04-19-rofi-140-sneak-preview-plugins.md\n    - Dynamic Theme: guides/DynamicThemes/dynamic_themes.md\n  - Current:\n    - Rofi: current/rofi.1.markdown \n    - Themes: current/rofi-theme.5.markdown\n    - Dmenu: current/rofi-dmenu.5.markdown\n    - Script: current/rofi-script.5.markdown\n    - Debugging: current/rofi-debugging.5.markdown\n    - Keys: current/rofi-keys.5.markdown\n    - Thumbnails: current/rofi-thumbnails.5.markdown\n    - Actions: current/rofi-actions.5.markdown\n  - 2.0.0:\n    - Rofi: 2.0.0/rofi.1.markdown \n    - Themes: 2.0.0/rofi-theme.5.markdown\n    - Dmenu: 2.0.0/rofi-dmenu.5.markdown\n    - Script: 2.0.0/rofi-script.5.markdown\n    - Debugging: 2.0.0/rofi-debugging.5.markdown\n    - Keys: 2.0.0/rofi-keys.5.markdown\n    - Thumbnails: 2.0.0/rofi-thumbnails.5.markdown\n    - actions: 2.0.0/rofi-actions.5.markdown\n  - 1.7.9:\n    - Rofi: 1.7.9/rofi.1.markdown \n    - Themes: 1.7.9/rofi-theme.5.markdown\n    - Dmenu: 1.7.9/rofi-dmenu.5.markdown\n    - Script: 1.7.9/rofi-script.5.markdown\n    - Debugging: 1.7.9/rofi-debugging.5.markdown\n    - Keys: 1.7.9/rofi-keys.5.markdown\n    - Thumbnails: 1.7.9/rofi-thumbnails.5.markdown\n  - 1.7.8:\n    - Rofi: 1.7.8/rofi.1.markdown \n    - Themes: 1.7.8/rofi-theme.5.markdown\n    - Dmenu: 1.7.8/rofi-dmenu.5.markdown\n    - Script: 1.7.8/rofi-script.5.markdown\n    - Debugging: 1.7.8/rofi-debugging.5.markdown\n    - Keys: 1.7.8/rofi-keys.5.markdown\n    - Thumbnails: 1.7.8/rofi-thumbnails.5.markdown\n  - 1.7.7:\n    - Rofi: 1.7.7/rofi.1.markdown \n    - Themes: 1.7.7/rofi-theme.5.markdown\n    - Dmenu: 1.7.7/rofi-dmenu.5.markdown\n    - Script: 1.7.7/rofi-script.5.markdown\n    - Debugging: 1.7.7/rofi-debugging.5.markdown\n    - Keys: 1.7.7/rofi-keys.5.markdown\n    - Thumbnails: 1.7.7/rofi-thumbnails.5.markdown\n  - 1.7.6:\n    - Rofi: 1.7.6/rofi.1.markdown \n    - Themes: 1.7.6/rofi-theme.5.markdown\n    - Dmenu: 1.7.6/rofi-dmenu.5.markdown\n    - Script: 1.7.6/rofi-script.5.markdown\n    - Debugging: 1.7.6/rofi-debugging.5.markdown\n    - Keys: 1.7.6/rofi-keys.5.markdown\n    - Thumbnails: 1.7.6/rofi-thumbnails.5.markdown\n  - 1.7.5:\n    - Rofi: 1.7.5/rofi.1.markdown \n    - Themes: 1.7.5/rofi-theme.5.markdown\n    - Dmenu: 1.7.5/rofi-dmenu.5.markdown\n    - Script: 1.7.5/rofi-script.5.markdown\n    - Debugging: 1.7.5/rofi-debugging.5.markdown\n    - Keys: 1.7.5/rofi-keys.5.markdown\n  - 1.7.4:\n    - Rofi: 1.7.4/rofi.1.markdown \n    - Themes: 1.7.4/rofi-theme.5.markdown\n    - Dmenu: 1.7.4/rofi-dmenu.5.markdown\n    - Script: 1.7.4/rofi-script.5.markdown\n    - Debugging: 1.7.4/rofi-debugging.5.markdown\n    - Keys: 1.7.4/rofi-keys.5.markdown\n  - 1.7.3:\n    - Rofi: 1.7.3/rofi.1.markdown \n    - Themes: 1.7.3/rofi-theme.5.markdown\n    - Dmenu: 1.7.3/rofi-dmenu.5.markdown\n    - Script: 1.7.3/rofi-script.5.markdown\n    - Debugging: 1.7.3/rofi-debugging.5.markdown\n    - Keys: 1.7.3/rofi-keys.5.markdown\n  - 1.7.2:\n    - Rofi: 1.7.2/rofi.1.markdown \n    - Themes: 1.7.2/rofi-theme.5.markdown\n    - Script: 1.7.2/rofi-script.5.markdown\n  - 1.7.1:\n    - Rofi: 1.7.1/rofi.1.markdown \n    - Themes: 1.7.1/rofi-theme.5.markdown\n    - Script: 1.7.1/rofi-script.5.markdown\n  - 1.7.0:\n    - Rofi: 1.7.0/rofi.1.markdown \n    - Themes: 1.7.0/rofi-theme.5.markdown\n    - Script: 1.7.0/rofi-script.5.markdown\n\nplugins:\n  - search:\n      indexing: full\n"
  },
  {
    "path": "pkgconfig/rofi.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\npluginsdir=@libdir@/rofi/\n\nName: rofi\nDescription: Header files for rofi plugins\nRequires.private: glib-2.0 >= 2.40 gmodule-2.0 cairo pango\nVersion: @VERSION@\nCflags: -I${includedir}/\n"
  },
  {
    "path": "protocols/wlr-foreign-toplevel-management-unstable-v1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<protocol name=\"wlr_foreign_toplevel_management_unstable_v1\">\n  <copyright>\n    Copyright © 2018 Ilia Bozhinov\n\n    Permission to use, copy, modify, distribute, and sell this\n    software and its documentation for any purpose is hereby granted\n    without fee, provided that the above copyright notice appear in\n    all copies and that both that copyright notice and this permission\n    notice appear in supporting documentation, and that the name of\n    the copyright holders not be used in advertising or publicity\n    pertaining to distribution of the software without specific,\n    written prior permission.  The copyright holders make no\n    representations about the suitability of this software for any\n    purpose.  It is provided \"as is\" without express or implied\n    warranty.\n\n    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS\n    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\n    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\n    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n    THIS SOFTWARE.\n  </copyright>\n\n  <interface name=\"zwlr_foreign_toplevel_manager_v1\" version=\"3\">\n    <description summary=\"list and control opened apps\">\n      The purpose of this protocol is to enable the creation of taskbars\n      and docks by providing them with a list of opened applications and\n      letting them request certain actions on them, like maximizing, etc.\n\n      After a client binds the zwlr_foreign_toplevel_manager_v1, each opened\n      toplevel window will be sent via the toplevel event\n    </description>\n\n    <event name=\"toplevel\">\n      <description summary=\"a toplevel has been created\">\n        This event is emitted whenever a new toplevel window is created. It\n        is emitted for all toplevels, regardless of the app that has created\n        them.\n\n        All initial details of the toplevel(title, app_id, states, etc.) will\n        be sent immediately after this event via the corresponding events in\n        zwlr_foreign_toplevel_handle_v1.\n      </description>\n      <arg name=\"toplevel\" type=\"new_id\" interface=\"zwlr_foreign_toplevel_handle_v1\"/>\n    </event>\n\n    <request name=\"stop\">\n      <description summary=\"stop sending events\">\n        Indicates the client no longer wishes to receive events for new toplevels.\n        However the compositor may emit further toplevel_created events, until\n        the finished event is emitted.\n\n        The client must not send any more requests after this one.\n      </description>\n    </request>\n\n    <event name=\"finished\" type=\"destructor\">\n      <description summary=\"the compositor has finished with the toplevel manager\">\n        This event indicates that the compositor is done sending events to the\n        zwlr_foreign_toplevel_manager_v1. The server will destroy the object\n        immediately after sending this request, so it will become invalid and\n        the client should free any resources associated with it.\n      </description>\n    </event>\n  </interface>\n\n  <interface name=\"zwlr_foreign_toplevel_handle_v1\" version=\"3\">\n    <description summary=\"an opened toplevel\">\n      A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel\n      window. Each app may have multiple opened toplevels.\n\n      Each toplevel has a list of outputs it is visible on, conveyed to the\n      client with the output_enter and output_leave events.\n    </description>\n\n    <event name=\"title\">\n      <description summary=\"title change\">\n        This event is emitted whenever the title of the toplevel changes.\n      </description>\n      <arg name=\"title\" type=\"string\"/>\n    </event>\n\n    <event name=\"app_id\">\n      <description summary=\"app-id change\">\n        This event is emitted whenever the app-id of the toplevel changes.\n      </description>\n      <arg name=\"app_id\" type=\"string\"/>\n    </event>\n\n    <event name=\"output_enter\">\n      <description summary=\"toplevel entered an output\">\n        This event is emitted whenever the toplevel becomes visible on\n        the given output. A toplevel may be visible on multiple outputs.\n      </description>\n      <arg name=\"output\" type=\"object\" interface=\"wl_output\"/>\n    </event>\n\n    <event name=\"output_leave\">\n      <description summary=\"toplevel left an output\">\n        This event is emitted whenever the toplevel stops being visible on\n        the given output. It is guaranteed that an entered-output event\n        with the same output has been emitted before this event.\n      </description>\n      <arg name=\"output\" type=\"object\" interface=\"wl_output\"/>\n    </event>\n\n    <request name=\"set_maximized\">\n      <description summary=\"requests that the toplevel be maximized\">\n        Requests that the toplevel be maximized. If the maximized state actually\n        changes, this will be indicated by the state event.\n      </description>\n    </request>\n\n    <request name=\"unset_maximized\">\n      <description summary=\"requests that the toplevel be unmaximized\">\n        Requests that the toplevel be unmaximized. If the maximized state actually\n        changes, this will be indicated by the state event.\n      </description>\n    </request>\n\n    <request name=\"set_minimized\">\n      <description summary=\"requests that the toplevel be minimized\">\n        Requests that the toplevel be minimized. If the minimized state actually\n        changes, this will be indicated by the state event.\n      </description>\n    </request>\n\n    <request name=\"unset_minimized\">\n      <description summary=\"requests that the toplevel be unminimized\">\n        Requests that the toplevel be unminimized. If the minimized state actually\n        changes, this will be indicated by the state event.\n      </description>\n    </request>\n\n    <request name=\"activate\">\n      <description summary=\"activate the toplevel\">\n        Request that this toplevel be activated on the given seat.\n        There is no guarantee the toplevel will be actually activated.\n      </description>\n      <arg name=\"seat\" type=\"object\" interface=\"wl_seat\"/>\n    </request>\n\n    <enum name=\"state\">\n      <description summary=\"types of states on the toplevel\">\n        The different states that a toplevel can have. These have the same meaning\n        as the states with the same names defined in xdg-toplevel\n      </description>\n\n      <entry name=\"maximized\"  value=\"0\" summary=\"the toplevel is maximized\"/>\n      <entry name=\"minimized\"  value=\"1\" summary=\"the toplevel is minimized\"/>\n      <entry name=\"activated\"  value=\"2\" summary=\"the toplevel is active\"/>\n      <entry name=\"fullscreen\" value=\"3\" summary=\"the toplevel is fullscreen\" since=\"2\"/>\n    </enum>\n\n    <event name=\"state\">\n      <description summary=\"the toplevel state changed\">\n        This event is emitted immediately after the zlw_foreign_toplevel_handle_v1\n        is created and each time the toplevel state changes, either because of a\n        compositor action or because of a request in this protocol.\n      </description>\n\n      <arg name=\"state\" type=\"array\"/>\n    </event>\n\n    <event name=\"done\">\n      <description summary=\"all information about the toplevel has been sent\">\n        This event is sent after all changes in the toplevel state have been\n        sent.\n\n        This allows changes to the zwlr_foreign_toplevel_handle_v1 properties\n        to be seen as atomic, even if they happen via multiple events.\n      </description>\n    </event>\n\n    <request name=\"close\">\n      <description summary=\"request that the toplevel be closed\">\n        Send a request to the toplevel to close itself. The compositor would\n        typically use a shell-specific method to carry out this request, for\n        example by sending the xdg_toplevel.close event. However, this gives\n        no guarantees the toplevel will actually be destroyed. If and when\n        this happens, the zwlr_foreign_toplevel_handle_v1.closed event will\n        be emitted.\n      </description>\n    </request>\n\n    <request name=\"set_rectangle\">\n      <description summary=\"the rectangle which represents the toplevel\">\n        The rectangle of the surface specified in this request corresponds to\n        the place where the app using this protocol represents the given toplevel.\n        It can be used by the compositor as a hint for some operations, e.g\n        minimizing. The client is however not required to set this, in which\n        case the compositor is free to decide some default value.\n\n        If the client specifies more than one rectangle, only the last one is\n        considered.\n\n        The dimensions are given in surface-local coordinates.\n        Setting width=height=0 removes the already-set rectangle.\n      </description>\n\n      <arg name=\"surface\" type=\"object\" interface=\"wl_surface\"/>\n      <arg name=\"x\" type=\"int\"/>\n      <arg name=\"y\" type=\"int\"/>\n      <arg name=\"width\" type=\"int\"/>\n      <arg name=\"height\" type=\"int\"/>\n    </request>\n\n    <enum name=\"error\">\n      <entry name=\"invalid_rectangle\" value=\"0\"\n        summary=\"the provided rectangle is invalid\"/>\n    </enum>\n\n    <event name=\"closed\">\n      <description summary=\"this toplevel has been destroyed\">\n        This event means the toplevel has been destroyed. It is guaranteed there\n        won't be any more events for this zwlr_foreign_toplevel_handle_v1. The\n        toplevel itself becomes inert so any requests will be ignored except the\n        destroy request.\n      </description>\n    </event>\n\n    <request name=\"destroy\" type=\"destructor\">\n      <description summary=\"destroy the zwlr_foreign_toplevel_handle_v1 object\">\n        Destroys the zwlr_foreign_toplevel_handle_v1 object.\n\n        This request should be called either when the client does not want to\n        use the toplevel anymore or after the closed event to finalize the\n        destruction of the object.\n      </description>\n    </request>\n\n    <!-- Version 2 additions -->\n\n    <request name=\"set_fullscreen\" since=\"2\">\n      <description summary=\"request that the toplevel be fullscreened\">\n        Requests that the toplevel be fullscreened on the given output. If the\n        fullscreen state and/or the outputs the toplevel is visible on actually\n        change, this will be indicated by the state and output_enter/leave\n        events.\n\n        The output parameter is only a hint to the compositor. Also, if output\n        is NULL, the compositor should decide which output the toplevel will be\n        fullscreened on, if at all.\n      </description>\n      <arg name=\"output\" type=\"object\" interface=\"wl_output\" allow-null=\"true\"/>\n    </request>\n\n    <request name=\"unset_fullscreen\" since=\"2\">\n      <description summary=\"request that the toplevel be unfullscreened\">\n        Requests that the toplevel be unfullscreened. If the fullscreen state\n        actually changes, this will be indicated by the state event.\n      </description>\n    </request>\n\n    <!-- Version 3 additions -->\n\n    <event name=\"parent\" since=\"3\">\n      <description summary=\"parent change\">\n        This event is emitted whenever the parent of the toplevel changes.\n\n        No event is emitted when the parent handle is destroyed by the client.\n      </description>\n      <arg name=\"parent\" type=\"object\" interface=\"zwlr_foreign_toplevel_handle_v1\" allow-null=\"true\"/>\n    </event>\n  </interface>\n</protocol>\n"
  },
  {
    "path": "protocols/wlr-layer-shell-unstable-v1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<protocol name=\"wlr_layer_shell_unstable_v1\">\n  <copyright>\n    Copyright © 2017 Drew DeVault\n\n    Permission to use, copy, modify, distribute, and sell this\n    software and its documentation for any purpose is hereby granted\n    without fee, provided that the above copyright notice appear in\n    all copies and that both that copyright notice and this permission\n    notice appear in supporting documentation, and that the name of\n    the copyright holders not be used in advertising or publicity\n    pertaining to distribution of the software without specific,\n    written prior permission.  The copyright holders make no\n    representations about the suitability of this software for any\n    purpose.  It is provided \"as is\" without express or implied\n    warranty.\n\n    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS\n    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\n    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\n    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n    THIS SOFTWARE.\n  </copyright>\n\n  <interface name=\"zwlr_layer_shell_v1\" version=\"5\">\n    <description summary=\"create surfaces that are layers of the desktop\">\n      Clients can use this interface to assign the surface_layer role to\n      wl_surfaces. Such surfaces are assigned to a \"layer\" of the output and\n      rendered with a defined z-depth respective to each other. They may also be\n      anchored to the edges and corners of a screen and specify input handling\n      semantics. This interface should be suitable for the implementation of\n      many desktop shell components, and a broad number of other applications\n      that interact with the desktop.\n    </description>\n\n    <request name=\"get_layer_surface\">\n      <description summary=\"create a layer_surface from a surface\">\n        Create a layer surface for an existing surface. This assigns the role of\n        layer_surface, or raises a protocol error if another role is already\n        assigned.\n\n        Creating a layer surface from a wl_surface which has a buffer attached\n        or committed is a client error, and any attempts by a client to attach\n        or manipulate a buffer prior to the first layer_surface.configure call\n        must also be treated as errors.\n\n        After creating a layer_surface object and setting it up, the client\n        must perform an initial commit without any buffer attached.\n        The compositor will reply with a layer_surface.configure event.\n        The client must acknowledge it and is then allowed to attach a buffer\n        to map the surface.\n\n        You may pass NULL for output to allow the compositor to decide which\n        output to use. Generally this will be the one that the user most\n        recently interacted with.\n\n        Clients can specify a namespace that defines the purpose of the layer\n        surface.\n      </description>\n      <arg name=\"id\" type=\"new_id\" interface=\"zwlr_layer_surface_v1\"/>\n      <arg name=\"surface\" type=\"object\" interface=\"wl_surface\"/>\n      <arg name=\"output\" type=\"object\" interface=\"wl_output\" allow-null=\"true\"/>\n      <arg name=\"layer\" type=\"uint\" enum=\"layer\" summary=\"layer to add this surface to\"/>\n      <arg name=\"namespace\" type=\"string\" summary=\"namespace for the layer surface\"/>\n    </request>\n\n    <enum name=\"error\">\n      <entry name=\"role\" value=\"0\" summary=\"wl_surface has another role\"/>\n      <entry name=\"invalid_layer\" value=\"1\" summary=\"layer value is invalid\"/>\n      <entry name=\"already_constructed\" value=\"2\" summary=\"wl_surface has a buffer attached or committed\"/>\n    </enum>\n\n    <enum name=\"layer\">\n      <description summary=\"available layers for surfaces\">\n        These values indicate which layers a surface can be rendered in. They\n        are ordered by z depth, bottom-most first. Traditional shell surfaces\n        will typically be rendered between the bottom and top layers.\n        Fullscreen shell surfaces are typically rendered at the top layer.\n        Multiple surfaces can share a single layer, and ordering within a\n        single layer is undefined.\n      </description>\n\n      <entry name=\"background\" value=\"0\"/>\n      <entry name=\"bottom\" value=\"1\"/>\n      <entry name=\"top\" value=\"2\"/>\n      <entry name=\"overlay\" value=\"3\"/>\n    </enum>\n\n    <!-- Version 3 additions -->\n\n    <request name=\"destroy\" type=\"destructor\" since=\"3\">\n      <description summary=\"destroy the layer_shell object\">\n        This request indicates that the client will not use the layer_shell\n        object any more. Objects that have been created through this instance\n        are not affected.\n      </description>\n    </request>\n  </interface>\n\n  <interface name=\"zwlr_layer_surface_v1\" version=\"5\">\n    <description summary=\"layer metadata interface\">\n      An interface that may be implemented by a wl_surface, for surfaces that\n      are designed to be rendered as a layer of a stacked desktop-like\n      environment.\n\n      Layer surface state (layer, size, anchor, exclusive zone,\n      margin, interactivity) is double-buffered, and will be applied at the\n      time wl_surface.commit of the corresponding wl_surface is called.\n\n      Attaching a null buffer to a layer surface unmaps it.\n\n      Unmapping a layer_surface means that the surface cannot be shown by the\n      compositor until it is explicitly mapped again. The layer_surface\n      returns to the state it had right after layer_shell.get_layer_surface.\n      The client can re-map the surface by performing a commit without any\n      buffer attached, waiting for a configure event and handling it as usual.\n    </description>\n\n    <request name=\"set_size\">\n      <description summary=\"sets the size of the surface\">\n        Sets the size of the surface in surface-local coordinates. The\n        compositor will display the surface centered with respect to its\n        anchors.\n\n        If you pass 0 for either value, the compositor will assign it and\n        inform you of the assignment in the configure event. You must set your\n        anchor to opposite edges in the dimensions you omit; not doing so is a\n        protocol error. Both values are 0 by default.\n\n        Size is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"width\" type=\"uint\"/>\n      <arg name=\"height\" type=\"uint\"/>\n    </request>\n\n    <request name=\"set_anchor\">\n      <description summary=\"configures the anchor point of the surface\">\n        Requests that the compositor anchor the surface to the specified edges\n        and corners. If two orthogonal edges are specified (e.g. 'top' and\n        'left'), then the anchor point will be the intersection of the edges\n        (e.g. the top left corner of the output); otherwise the anchor point\n        will be centered on that edge, or in the center if none is specified.\n\n        Anchor is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"anchor\" type=\"uint\" enum=\"anchor\"/>\n    </request>\n\n    <request name=\"set_exclusive_zone\">\n      <description summary=\"configures the exclusive geometry of this surface\">\n        Requests that the compositor avoids occluding an area with other\n        surfaces. The compositor's use of this information is\n        implementation-dependent - do not assume that this region will not\n        actually be occluded.\n\n        A positive value is only meaningful if the surface is anchored to one\n        edge or an edge and both perpendicular edges. If the surface is not\n        anchored, anchored to only two perpendicular edges (a corner), anchored\n        to only two parallel edges or anchored to all edges, a positive value\n        will be treated the same as zero.\n\n        A positive zone is the distance from the edge in surface-local\n        coordinates to consider exclusive.\n\n        Surfaces that do not wish to have an exclusive zone may instead specify\n        how they should interact with surfaces that do. If set to zero, the\n        surface indicates that it would like to be moved to avoid occluding\n        surfaces with a positive exclusive zone. If set to -1, the surface\n        indicates that it would not like to be moved to accommodate for other\n        surfaces, and the compositor should extend it all the way to the edges\n        it is anchored to.\n\n        For example, a panel might set its exclusive zone to 10, so that\n        maximized shell surfaces are not shown on top of it. A notification\n        might set its exclusive zone to 0, so that it is moved to avoid\n        occluding the panel, but shell surfaces are shown underneath it. A\n        wallpaper or lock screen might set their exclusive zone to -1, so that\n        they stretch below or over the panel.\n\n        The default value is 0.\n\n        Exclusive zone is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"zone\" type=\"int\"/>\n    </request>\n\n    <request name=\"set_margin\">\n      <description summary=\"sets a margin from the anchor point\">\n        Requests that the surface be placed some distance away from the anchor\n        point on the output, in surface-local coordinates. Setting this value\n        for edges you are not anchored to has no effect.\n\n        The exclusive zone includes the margin.\n\n        Margin is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"top\" type=\"int\"/>\n      <arg name=\"right\" type=\"int\"/>\n      <arg name=\"bottom\" type=\"int\"/>\n      <arg name=\"left\" type=\"int\"/>\n    </request>\n\n    <enum name=\"keyboard_interactivity\">\n      <description summary=\"types of keyboard interaction possible for a layer shell surface\">\n        Types of keyboard interaction possible for layer shell surfaces. The\n        rationale for this is twofold: (1) some applications are not interested\n        in keyboard events and not allowing them to be focused can improve the\n        desktop experience; (2) some applications will want to take exclusive\n        keyboard focus.\n      </description>\n\n      <entry name=\"none\" value=\"0\">\n        <description summary=\"no keyboard focus is possible\">\n          This value indicates that this surface is not interested in keyboard\n          events and the compositor should never assign it the keyboard focus.\n\n          This is the default value, set for newly created layer shell surfaces.\n\n          This is useful for e.g. desktop widgets that display information or\n          only have interaction with non-keyboard input devices.\n        </description>\n      </entry>\n      <entry name=\"exclusive\" value=\"1\">\n        <description summary=\"request exclusive keyboard focus\">\n          Request exclusive keyboard focus if this surface is above the shell surface layer.\n\n          For the top and overlay layers, the seat will always give\n          exclusive keyboard focus to the top-most layer which has keyboard\n          interactivity set to exclusive. If this layer contains multiple\n          surfaces with keyboard interactivity set to exclusive, the compositor\n          determines the one receiving keyboard events in an implementation-\n          defined manner. In this case, no guarantee is made when this surface\n          will receive keyboard focus (if ever).\n\n          For the bottom and background layers, the compositor is allowed to use\n          normal focus semantics.\n\n          This setting is mainly intended for applications that need to ensure\n          they receive all keyboard events, such as a lock screen or a password\n          prompt.\n        </description>\n      </entry>\n      <entry name=\"on_demand\" value=\"2\" since=\"4\">\n        <description summary=\"request regular keyboard focus semantics\">\n          This requests the compositor to allow this surface to be focused and\n          unfocused by the user in an implementation-defined manner. The user\n          should be able to unfocus this surface even regardless of the layer\n          it is on.\n\n          Typically, the compositor will want to use its normal mechanism to\n          manage keyboard focus between layer shell surfaces with this setting\n          and regular toplevels on the desktop layer (e.g. click to focus).\n          Nevertheless, it is possible for a compositor to require a special\n          interaction to focus or unfocus layer shell surfaces (e.g. requiring\n          a click even if focus follows the mouse normally, or providing a\n          keybinding to switch focus between layers).\n\n          This setting is mainly intended for desktop shell components (e.g.\n          panels) that allow keyboard interaction. Using this option can allow\n          implementing a desktop shell that can be fully usable without the\n          mouse.\n        </description>\n      </entry>\n    </enum>\n\n    <request name=\"set_keyboard_interactivity\">\n      <description summary=\"requests keyboard events\">\n        Set how keyboard events are delivered to this surface. By default,\n        layer shell surfaces do not receive keyboard events; this request can\n        be used to change this.\n\n        This setting is inherited by child surfaces set by the get_popup\n        request.\n\n        Layer surfaces receive pointer, touch, and tablet events normally. If\n        you do not want to receive them, set the input region on your surface\n        to an empty region.\n\n        Keyboard interactivity is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"keyboard_interactivity\" type=\"uint\" enum=\"keyboard_interactivity\"/>\n    </request>\n\n    <request name=\"get_popup\">\n      <description summary=\"assign this layer_surface as an xdg_popup parent\">\n        This assigns an xdg_popup's parent to this layer_surface.  This popup\n        should have been created via xdg_surface::get_popup with the parent set\n        to NULL, and this request must be invoked before committing the popup's\n        initial state.\n\n        See the documentation of xdg_popup for more details about what an\n        xdg_popup is and how it is used.\n      </description>\n      <arg name=\"popup\" type=\"object\" interface=\"xdg_popup\"/>\n    </request>\n\n    <request name=\"ack_configure\">\n      <description summary=\"ack a configure event\">\n        When a configure event is received, if a client commits the\n        surface in response to the configure event, then the client\n        must make an ack_configure request sometime before the commit\n        request, passing along the serial of the configure event.\n\n        If the client receives multiple configure events before it\n        can respond to one, it only has to ack the last configure event.\n\n        A client is not required to commit immediately after sending\n        an ack_configure request - it may even ack_configure several times\n        before its next surface commit.\n\n        A client may send multiple ack_configure requests before committing, but\n        only the last request sent before a commit indicates which configure\n        event the client really is responding to.\n      </description>\n      <arg name=\"serial\" type=\"uint\" summary=\"the serial from the configure event\"/>\n    </request>\n\n    <request name=\"destroy\" type=\"destructor\">\n      <description summary=\"destroy the layer_surface\">\n        This request destroys the layer surface.\n      </description>\n    </request>\n\n    <event name=\"configure\">\n      <description summary=\"suggest a surface change\">\n        The configure event asks the client to resize its surface.\n\n        Clients should arrange their surface for the new states, and then send\n        an ack_configure request with the serial sent in this configure event at\n        some point before committing the new surface.\n\n        The client is free to dismiss all but the last configure event it\n        received.\n\n        The width and height arguments specify the size of the window in\n        surface-local coordinates.\n\n        The size is a hint, in the sense that the client is free to ignore it if\n        it doesn't resize, pick a smaller size (to satisfy aspect ratio or\n        resize in steps of NxM pixels). If the client picks a smaller size and\n        is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the\n        surface will be centered on this axis.\n\n        If the width or height arguments are zero, it means the client should\n        decide its own window dimension.\n      </description>\n      <arg name=\"serial\" type=\"uint\"/>\n      <arg name=\"width\" type=\"uint\"/>\n      <arg name=\"height\" type=\"uint\"/>\n    </event>\n\n    <event name=\"closed\">\n      <description summary=\"surface should be closed\">\n        The closed event is sent by the compositor when the surface will no\n        longer be shown. The output may have been destroyed or the user may\n        have asked for it to be removed. Further changes to the surface will be\n        ignored. The client should destroy the resource after receiving this\n        event, and create a new surface if they so choose.\n      </description>\n    </event>\n\n    <enum name=\"error\">\n      <entry name=\"invalid_surface_state\" value=\"0\" summary=\"provided surface state is invalid\"/>\n      <entry name=\"invalid_size\" value=\"1\" summary=\"size is invalid\"/>\n      <entry name=\"invalid_anchor\" value=\"2\" summary=\"anchor bitfield is invalid\"/>\n      <entry name=\"invalid_keyboard_interactivity\" value=\"3\" summary=\"keyboard interactivity is invalid\"/>\n      <entry name=\"invalid_exclusive_edge\" value=\"4\" summary=\"exclusive edge is invalid given the surface anchors\"/>\n    </enum>\n\n    <enum name=\"anchor\" bitfield=\"true\">\n      <entry name=\"top\" value=\"1\" summary=\"the top edge of the anchor rectangle\"/>\n      <entry name=\"bottom\" value=\"2\" summary=\"the bottom edge of the anchor rectangle\"/>\n      <entry name=\"left\" value=\"4\" summary=\"the left edge of the anchor rectangle\"/>\n      <entry name=\"right\" value=\"8\" summary=\"the right edge of the anchor rectangle\"/>\n    </enum>\n\n    <!-- Version 2 additions -->\n\n    <request name=\"set_layer\" since=\"2\">\n      <description summary=\"change the layer of the surface\">\n        Change the layer that the surface is rendered on.\n\n        Layer is double-buffered, see wl_surface.commit.\n      </description>\n      <arg name=\"layer\" type=\"uint\" enum=\"zwlr_layer_shell_v1.layer\" summary=\"layer to move this surface to\"/>\n    </request>\n\n    <!-- Version 5 additions -->\n\n    <request name=\"set_exclusive_edge\" since=\"5\">\n      <description summary=\"set the edge the exclusive zone will be applied to\">\n        Requests an edge for the exclusive zone to apply. The exclusive\n        edge will be automatically deduced from anchor points when possible,\n        but when the surface is anchored to a corner, it will be necessary\n        to set it explicitly to disambiguate, as it is not possible to deduce\n        which one of the two corner edges should be used.\n\n        The edge must be one the surface is anchored to, otherwise the\n        invalid_exclusive_edge protocol error will be raised.\n      </description>\n      <arg name=\"edge\" type=\"uint\" enum=\"anchor\"/>\n    </request>\n  </interface>\n</protocol>\n"
  },
  {
    "path": "releasenotes/0.15.12/release-0.15.12.markdown",
    "content": "# Release 0.15.12\n\nThe 0.15.12 release of **rofi** focusses on improving overall user experience.  These improvements mostly focussed on\nthree things, first we (tried to) fix the problems with complex keyboard layouts, second we tried to make theming of\n**rofi** easier. Also we added several speedups. Below I will highlight these bigger changes in more details\n\nNow that **rofi** reached an acceptable maturity level, we will start using more common\nversion numbering. Right now rofi uses `0.year.month` for version numbers.\nStarting with next version the widely used `major.minor.bugfix` scheme will be used.\nThis means, that next rofi version will either be\n\n* 0.15.13 (bugfix release)\n* 0.16.0 (minor release) or (if no major bugs are discovered)\n* 1.0.0 (major release)\n\n## Keyboard Layouts\n\n**Rofi** used to have problems with keyboard layouts that used modifier keys to switch between different layers.\nThese problems should now be a thing of the past.\n\n**Note** the syntax for binding keys has slightly changed. The *Mod1*, *Mod2*, etc. keywords are no longer available.\nThere was no good way to detect how these keys where mapped and if they could be used as modifiers.  E.g. if the right\nalt (say *Mod3*) is configured to switch between layouts, it cannot work as modifier key to make a `Mod3-p` keybinding.\n**Rofi** will now check if the current layout has the *SuperR*,*SuperL*,*AltGr*,*HyperL*,*HyperR* keys available.  If\nthey are available they can be used for keybindings, if not, the user gets a warning.\n\n![Rofi Keyboard Warning](rofi-warning.png)\n\n## Speedups\n\n### DMenu reading from stdin\n\n**Rofi** used to have a custom `fgets` implementation that supported custom separators. The has been replaced by the\n`getdelim` feature of POSIX '08, this gave a speedup of 6x (from 648 ms for 202000 lines down to 108ms).\n\n### Multi-Core power\n\nStill disabled by default, **rofi** can now spawn multiple threads for filtering rows. Depending on the underlying\nhardware we saw a 1.5x speedup running on a dual core ARM and up to a 3.5x speedup on a quadcore (8 threads) i7 CPU.\nIt uses Glib's GThreadPool and will therefore spawn threads as needed and clean them up again afterwards.\n\nTo enable this option pass the `-threads 0` option, this will autodetect the number number of hw-threads. Pass `-threads 4`\nto force it to use 4 threads. Setting the number to 1, disables it.\n\n\n## Themes\n\n**Rofi** color themes can be specified in a lot of detail, including the use of transparency to get desired results.\nHowever color syntax proved to be difficult and testing it can be a hassle. To solve this we added a web frontend for writing\nthemes (with live preview) and a themes repository.\n\nTo make things even easier, you can now take screenshots of **rofi** from within **rofi** with a simple keybinding.\n\n![Rofi Internal Screenshot](rofi-screenshot.png)\n\n### Theme repository\n\nThis has been requested several times and rofi's website actually has a theming page. This however got outdated quickly\nand neither the themes or the screenshots are correct anymore. The newly added rofi-themes git repository allows you to\nadd themes easily: Fork the repository and export your current color theme with **rofi -dump-xresources-theme**. Place\nit in the theme directory of the repository and run the update script. This will automatically generate screenshots and\nupdate the page.  Update your fork and send a pull request. This way your theme will appear on official themes page,\nonce it's merged.\n\nThe repository can be found [here](https://github.com/DaveDavenport/rofi-themes/)\n\n![Rofi Theme Site](rofi-theme-site.png)\n\n### Themenator\n\nThe second tool is a website allowing you to easily create themes and preview all changes life, the\n[themenator](https://davedavenport.github.io/rofi/generator.html) Big thanks to\n[SardemFF7](https://github.com/sardemff7) who got tired of me complaining, took the very rough prototype and turned it\ninto something beautiful.\n\nHopefully people will make beautiful themes and submit them to the [theme repository](https://github.com/DaveDavenport/rofi-themes/).\n\n![Rofi Themenator](rofi-themenator.png)\n\n## Full ChangeLog\n\n### New features:\n- Initial `-dump` command for dmenu mode. (#216)\n- Threading support.\n    - Parallel checking for ASCII.\n    - Parallel string matching.\n    - Autodetect number of HW-threads.\n    - Disabled by default.\n- Highlight multiple selected rows (#287,#293)\n- Dmenu can read from file instead of stdin.\n- Regex matching (#113)\n- Take Screenshot of rofi using keybinding.\n- Hotkey for sorting: (#298)\n- Option to set scrollbar width.\n\n### Improvements:\n\n- Fix return code of multi-select.\n- Update manpage (#289, #291)\n- Improve speed of reading stdin in dmenu mode.\n- Correctly handle modifier keys now. Should now support most weird keyboard layouts and switching between them.\n(#268, #265, #286)\n- Correctly set locale, fixing issues with entering special characters. (#282)\n- DRun mode support `NoDisplay` setting (#283)\n- Pango markup is matched when filtering. (#273)\n\n### Bug fixes:\n\n- Improve error message (#290)\n- Correctly switch to next entry on multi-select when list is filtered (#292)\n- Switch __FUNCTION__ for __func__. (#288)\n- Fix segfault on empty list and moving through it. (#256,#275)\n- Fix one off of colors (#269)\n- Drun fix uninitialized memory (#285)\n"
  },
  {
    "path": "releasenotes/1.0.0/release-1.0.0.markdown",
    "content": "# V1.0.0 - Welcome in 2016\n\nThe new release, after a long development cycle, is finally out. It has a lot of changes that are hopefully invisible to\nthe user. On top of that we decided it is time to deprecate some old stuff left from the simpleswitcher era.\nThe biggest changes in this version are two major rewrites in the hope to improve maintainability and code quality.\n\nThe biggest changes in this release are:\n\n## XLib to xcb\n\nWith the help of SardemFF7 **rofi** we broke free from the massif xlib and moved to xcb. This resulted in cleaner and\nfaster code. To offer all the functionality offered by the xlib version, we do depend on a relatively new xkbcommon\n(0.5.0), luckily most distributions latest releases should be supporting this. In this move we manage to squash several\nlong standing bugs and open a possibility to fix more in the future.\n\n## GLib Mainloop\n\nBeside the large xcb move, we also started using a Glib Mainloop. This allowed us to remove several complex code\nstructures. This change should be mostly invisible for the user, beside the fact that the cursor in the entry box now\nblinks.\n\n## Config file\n\nNot everybody seems to like configuration via Xresources, so for those people we now support a configuration file in\n`XDG_CONFIG_HOME/rofi/config`, or passed from the commandline via the `-config` option. Settings in the config file will\noverride Xresources and is read on each startup.\n\n## Version scheme\n\nRofi now no longer uses 0.year.month as release number, but switches to a more common scheme:\n**major**.**minor**.**patch**. The release number 1.0.0 has no significant meaning, but was a logic followup on 0.15.12.\nWe added features and broke backwards compatibility.\n\n## Better locale and UTF-8 handling\n\nIn our continious effort of making **rofi** handle UTF-8 and locales correctly we made the run dialog convert to and\nfrom the locale filesystem encoding correctly, made the dmenu input parser more robust for handling invalid UTF-8 and do\nwe try to convert coming from Xorg.\n\n## \"Regression\"\n\nThere where also some victims of the big rewrite, we decided to remove an old remnants from the simpleswitcher era,\nnamely daemon mode. In our opinion this is duplicate functionality, if you are using **rofi** it is very likely you are\neither running a window manager (like i3) that implements global hotkey functionality, or running a keyboard daemon like\nsxhkd.\n\nA second victim, that had been marked deprecated for more then a year, is the old method of specifying themes where\nevery color option had one commandline flag. This method was very verbose and incomplete. With the [theme\nrepository](https://github.com/DaveDavenport/rofi-themes/) and the online [theme\ngenerator](https://davedavenport.github.io/rofi/p11-Generator.html) using and creating new themes should be easy enough.\n\n# Changelog\n\nBelow is a more complete changelog between the 0.15.12 and the 1.0.0 release.\n\n## New Features\n\n* Blinking cursor\n* Separate configuration file\n* History in drun mode (#343)\n* Context menu mode, show **rofi** at the mouse pointer\n\n## Improvement\n\n* auto select and single item on dmenu mode (#281)\n* Unlimited window title length.\n* Correctly follow the active desktop, instead of active window.\n* If requesting modi that is not enabled, show it anyway.\n* DMenu password mode. (#315)\n* Levenshtein sort is now UTF-8 aware.\n* Use xcb instead of large xlib library.\n* Use GLib mainloop for cleaner code and easier external event based handling in future.\n* Run dialog: Try to convert between locale, fs encoding and utf8. Fixing problems with non-utf8 filesystem encodings.\n* Try to display non-utf8 strings as good as possible.\n* Autocomplete bang hint in combi mode (#380)\n* Remove magic line length limits by switching to getline from fgets.\n* Print git version for git builds in version string.\n\n## Bug fixes\n\n* Fix subpixel rendering. (#303)\n* Fix basic tests on OpenBSD (#272)\n* Fix wrong use of memcpy (thx to Jasperia).\n* Work around for sigwaitinfo on OpenBSD.\n* Ignore invalid entries (non-utf8) in dmenu mode.\n* Glib signal handling.\n* Fix connecting to i3 on bsd.\n* Be able to distinguish between empty and cancel in dmenu mode. (#323)\n* Fix memcpy on single memory region. (#312)\n* Fix opening file with mode a+ and using fseek to overwrite on bsd.\n\n\n## Regressions\n\n* Removal of old themeing method. Given it was incomplete.\n* Removal of daemon mode, given this duplicates Window Manager functionality.\n"
  },
  {
    "path": "releasenotes/1.1.0/release-1.1.0.markdown",
    "content": "# V1.1.0 - A trump card\n\n## New Features\n\n    - Keys mode, showing keybindings.\n    - Stop cycling option (#407) (Thx to Yaroslav)\n    - Kill window on delete entry (#316)\n\n## Improvements\n\n    - Add Control+Backspace as remove word back keybinding.\n    - Allow user to use X11 background for fake transparency (#390)\n    - Allow user to specify background image.\n    - Improved keybinding handling, allowing on-release and modifier only (#384).\n    - Use display name for prompt (#409)\n    - Parse subdirectories in drun parser (#416)\n    - Switch to stop cycling (#407)\n\n## Bug fixes\n\n    - Grab mouse pointer with keyboard\n"
  },
  {
    "path": "releasenotes/1.2.0/release-1.2.0.markdown",
    "content": "# V1.2.0 - 8397\n\n## New Features\n\nDespite me saying after every release that it is mostly feature complete;  new **Rofi**, new features.\nHowever these new features are mostly to improve current functionality and debugging.\nBelow the 4 most important ones.\n\n### Underline Match\n\nA new, hopefully welcome, addition is that **Rofi** now highlights the match in each row:\n\n![Rofi Underline](./rofi-underline-match.png)\n\nTo accomplish this, now all matching is done using *GRegex*, as this returns the exact location in the string of each match.\nWhile I don't see a direct use, it is something a lot of other *quick search* tools provide, so **Rofi** could not stay\nbehind.\n\n## Multiline Select\n\nWhile already existing in a very rudimentary form, we now improved the multi-line select in **dmenu** mode. It will\nallow you to select and unselect rows, selected rows are highlighted with a dot and a small counter indicated the amount\nof rows selected.\n\n![Rofi Multi Select](./rofi-multi-select.png)\n\n## Customize Window string\n\nYou can now specify what the window switcher will show.\nIt allows for some markup to nicely line up the entries.\n\nFor example if the with of the window is specified in characters, this would right align the class name\n\n```\nrofi.window-format: {t:-16} ({c:10})\n```\n\n![Rofi Window title align](./rofi-window-align.png)\n\n## Track configuration option origin\n\n**Rofi** now keeps track of how configuration options are set. It will now display if it is the default value, set in\nXresources, configuration file or commandline.\n\n![Rofi configuration tracking](./rofi-options.png)\n\nThis should help debugging recent bugs, where people had an invalid `pid` path set in the configuration file.\nAdditionally if you dump the configuration, for using on another pc, it will comment the options that are set to their\ndefault value. (So f.e. pidfile location won't be overriden).\n\n## Bug Fixes\n\nAs no tool is without bugs, and **Rofi** not being the exception, we did manage to squash a few.\n\n* Fix current desktop window selector.\n* Fix launching application in terminal.\n* Support ```#include``` in config file.\n* Fix rofi on 30bit 10 bit per channel display.\n* Correct `Control-u` behaviour to remove till begin of line. `Control-w` now whipes the line.\n* Add missing `Control-k` keybinding, delete till end of line.\n\n## Remove features\n\n* Removed fuzzy finder\n* Remove **[i3](http://www.i3wm.org)** workarounds. As **i3** has, for more than a year now, native support for EWMH.\n* Remove **XLib** dependency. The last hard dependency on **Xlib** has been removed by the use of\n  **[xcb-util-xrm](https://github.com/Airblader/xcb-util-xrm)**.\n"
  },
  {
    "path": "releasenotes/1.3.0/release-1.3.0.markdown",
    "content": "# V1.3.0: Dan vs. Greg: The never ending story.\n\nThis release mostly focussed on cleaning up and refactoring the internals. One of the big changes is that the gui is no\nlonger based on hard-coded positions. We introduced a widget system with boxes, scrollbars, separators, listview and\ntextboxes.  The boxes (vertical and horizontal) allows us to nice structure the layout and have them resize according to\nrules when the window changes size.\n\n![structure](structure.png)\n\nThis allowed us to make changes at run-time. In the future I hope we can use this to improve the theming (think css like\nthemes).  The cleanup and refactoring is not finished and will continue for the next release.\n\nBeside this we still managed to get some new features in:\n\n## Dynamic window size\n\nEnabled by the refactoring, rofi can now resize the window to fit the number of visible entries, so as you type and the\nlist of options becomes small, so does the windows (this is disabled by default). Rofi will try to keep the text box at\nthe same place so you don't have to move focus, this means that at the bottom of the screen the window layout is\nreversed so the textbox is at the bottom.\n\n![Resize action](resize.gif)\n\n### Theme selector\n\nTo make it easier to get a good looking rofi, we included a theme-selector script and ship rofi with a set of themes.\nThe script allows you to preview themes, and make them the default theme.\n\n![Theme Selector](theme-selector.gif)\n\nIt seems byzanz (to record the gif) changes the colors a bit. It looks better in real-life.\n\n### Fuzzy parser\n\nOn many request, the fuzzy matcher has been re-added:\n\n![fuzzy](fuzzy.png)\n\n### ASync DMENU\n\nRofi can read input data for dmenu asynchronous from displaying. So if you have something that takes a time to produce,\nyou can see the progress, start filtering and selecting entries before it finishes.\nThis can be very useful when searching through large data sets.\nIn the below screenshot it keeps feeding rofi the content of the directory. Rofi indicates it is still receiving data by\nthe `loading...` text.\n\n![async](dmenu-async.png)\n\nAsync mode is not always possible, and will be disabled if not possible.\n\n### Drawing improvements\n\nIn this release rofi is more efficient in drawing its content to the X11 window. The basic redraw on expose has been\nspeedup by a factor 1000. This was obtained by using a server side copy of the internal surface, instead of painting it\nwith cairo each time. Especially for large (4k and higher) screens, in fullscreen mode, this reduces redrawing from +-\n180ms to 0.1 ms. A second improvement was made by configuring X11 not repaint the window background when resized, this\ncaused some flickering (it was painted black before being drawn). It now keeps the old content and tells rofi to\nrepaint. This causes trailing, but overall looks nicer.\n\n## Removals\n\nWe also removed a deprecated option, `-opacity`. Did option did full window opacity, basically it makes the whole window\nand text transparent. A very ugly effect. The current argb colors in the theme allow a nice transparency, where only the\nbackground of the window is transparent but not the text (you can still reproduce the old style in the new theme format,\nby making all colors transparent).\n\n\n## Detailed Changelog\n\n### New Features\n\n- Use randr for getting monitor layout. Fallback to xinerama if not available.\n- Re-add fuzzy matcher.\n- Restructure internal code to use dynamic sizing widgets. (hbox, vbox and lists)\n- Async mode for dmenu.\n- Add theme selector script.\n- Include 21 themes.\n- Dynamically sizing window with content.\n- When placed at bottom of screen re-order screen to have entry at bottom.\n\n### Improvements\n\n- Fix pasting secondary clipboard. (#516)\n- By default use all cores to filter entries.\n- Make sure drawing priority is higher then reading input data.\n- Improve resizing of window, don't make X whipe background.\n- Improve close window (shift-delete) action, by sending NET_WM_CLOSE instead of destroying window.\n- Create cache and run directory on startup. (#497)\n- Fix unneeded redraws on cursor blinking. (#491)\n- Improve time till grabbing keyboard. (#494)\n- Better error message when failing to parse keybindings, also continue parsing on error.\n- Fix problem with custom layouts (#485)\n- Speedup drawing of screen. Works well now for 4k and 8k screens. (factor 1000+ speedup for the flipping of buffer)\n  (#496)\n- DRun mode more compatible with specification.\n- Debug output via g_log.\n- Fix password entry cursor position.\n- Use bash instead of sh for get_git_rev.sh (#445)\n- Add Control+G for cancel (#452)\n- Add padding option to textbox (#449)\n- Ctrl-click does alternate accept entry. (#429)\n- Hide window decoration in normal window mode.\n- Click to exit option. (#460)\n- Fix cursor blinking on moving. (#462)\n- Remove entry from history if fails to execute (#466)\n- Fix margins. (#467)\n- Improved documentation of functions in code.\n- DRun: Set work directory when executing file. (#482)\n- Memory leak fixes.\n- Improve scrollbar behaviour.\n\n### Removals\n\n- opacity option. The transparency support in the theme can do the same and more.\n"
  },
  {
    "path": "releasenotes/1.3.1/release-1.3.1.markdown",
    "content": "# V1.3.1: Dan vs. Greg: The never ending story, reloaded.\n\nA quick follow up release to resolve some issues with copyright notices in the shipped **rofi** themes.\nBelow is the, modest, full list of changes.\n\n## Detailed Changelog\n\n### New Features\n\n- [DRun] Search categories. ([#449](https://github.com/DaveDavenport/rofi/issues/449))\n\n### Improvements\n\n- Fix exit when failed to grab keyboard. ([#524](https://github.com/DaveDavenport/rofi/issues/524))\n- Introduce lazy keyboard grab mode for people who want rofi to show on key-down in i3.\n- Add copyrights to theme (needed for debian packaging).\n- DMENU: Correctly detect end-of-file ([#518](https://github.com/DaveDavenport/rofi/issues/518))\n- Directly queue redraw on overlay change.\n- Remove pango markup from workspace names in I3. ([#507](https://github.com/DaveDavenport/rofi/issues/507))\n\n"
  },
  {
    "path": "releasenotes/1.4.0/release-1.4.0.markdown",
    "content": "# V1.4.0: I reject your truth and trumpstitute my own\n\n> This release contains some major changes. One of them being a new theme\n> engine. The migration from older versions to this version might not go\n> flawless.\n\nWith more then 750 commits since the last version, this is one of the biggest\nreleases so far.  In this version we used the groundwork laid in v1.3.0 and went\ncompletely nuts with it. Hopefully this release should satisfy the die-hard\ndesktop [ricers](https://www.reddit.com/r/unixporn/) with a brand new theme\nengine.  Lot of different colors, border, multiple fonts everything is now\npossible.\n\nBecause of The great work done by [SardemFF7](https://github.com/SardemFF7/) the\ncode base is simplified and the key and mouse handling improved. The libraries\nprovided by SardemFF7 also made it possible to add a often requested feature of\nicons (correctly using the icon-theme). A feature I never expected to be added.\nTo top this off, SardemFF7 added support to build rofi using\n[meson](http://mesonbuild.com/).\n\nA last big addition and still in beta, is support for plugins. Allowing the\naddition of some weird/fancy features.  Currently two plugins are available,\n[blezz](https://gitcrate.org/qtools/rofi-blezz) a quick launch menu with it own\nmenu definition and [top](https://gitcrate.org/qtools/rofi-top/) displaying\nrunning processes.\n\nBeside these major changes, this release includes a lot of bug-fixes and small\nimprovements. See the bottom of this release notes for a more complete list of\nchanges.\n\n\n## Theme engine\n\nThe biggest new feature of this release is the theme engine. Building on the\nchanges made in v1.3.0 we implemented a new theme engine and it has a completely\nnew theme format. While the themes are a lot more verbose now, it does allow for\na lot of extra customizations.\n\nIt is now possible to theme each widget in rofi independently:\n\n### Colors\n\nYou can now set the color on each widget independent in most of the CSS\nsupported color formats (hsl, cmyk, rgb, etc.) and each color can have a\ntransparency. There are three colors that can be set on each widget:\n\n*  **background-color**\n   Used to draw the background of the widget. Each widget is drawn on top of it\n   parent, if the background is transparent, you will see the parents widget.\n*  **border-color**\n   Used to draw the borders.\n*  **text-color**\n   Used to draw text. If not set the foreground color is used.\n\n![rainbox](rofi-rainbow.png)\n\n### Borders\n\nOn every widget we can now configure a border for each of the four sides, the\ncolor of the border, the style of the border (solid or dashed) and the radius of\nthe corners can be set.\n\n![border1](rofi-border.png)\n\nThis combined with (fake) transparency can make for a very nice looking, rounded\nrofi experience.\n\n![border2](rofi-border-transp.png)\n\n### Fonts\n\nAn often made request was support for different fonts for the entry box and the\nlist. With the new theme, it is possible to change the font and size of all\nwidgets.\n\n![fonts](rofi-fonts.png)\n\n> Note that opening a fonts is one of the slowest operations during rofi\n> startup; having multiple fonts could have a significant impact on startup\n> times.\n\n### Flexible layout\n\nTo top all these changes, as an advanced feature the whole layout of the window\ncan be changed. Making it possible to mimic the original dmenu view, or make it\nappear as a minimal context menu.\n\n![dmenu](rofi-dmenu.png)\n\n\n## Error reporting\n\nThe new theme parser will also be more verbose when encountering parsing errors,\nhopefully helping debugging and modifying themes.\n\nFor example when forgetting a trailing ';' will report where it failed, and what\nit expected (a ';').\n\n![rofi-error](rofi-error.png)\n\n## Importing\n\nThe new theme parser also support importing and overriding. This allow you to\nmake make modifications to an existing theme, without having to completely copy\nit. For example, I want to use the `arthur` theme (shipped with rofi) but use\nfake transparency, change the font off the result list and import a set of\noverriding colors from `mycolors`.\n\n```css\n// Import the default arthur theme\n@theme \"arthur\"\n\n// Load in overriding of colors from mycolors.\n@import \"mycolors\"\n\n/* on the window widget, set transparency to use a screenshot of the screen. */\n#window {\n    transparency: \"screenshot\";\n}\n/* Override the font on the listview elements */\n#element {\n    font: \"Ubuntu Mono 18\";\n}\n```\n\n## Icons\n\nAnother often made request, I never expected to be implemented, was icon\nsupport. With the help of SardemFF7 an implementation was possible that\ncorrectly follows the XDG icon specification and does not negatively impact the\nperformance. Currently the drun and the window switcher can application icons.\nTo enable icons, set the `show-icons` property to `true`.\n\n\n![icons](rofi-icons.png)\n\n\n## More flexible key and mouse bindings\n\nThanks to another great work of SardemFF7 you can now configure how the mouse\nbehave and bind modifier keys. It also improves on error messages. For example\nit will now detect duplicate bindings.\n\nFor example to select an entry on single click, instead of double click:\n\n```\nrofi -show run -me-select-entry '' -me-accept-entry 'Mouse1'\n```\n\n\n## Fuzzy Matching\n\nWith thanks to Fangrui Song, the `fuzzy` matcher will now use a ranking similar\nto `fzf` to sort the results.  This should hopefully to improve the results,\nsomething a lot of users will appreciate.\n\nWithout:\n\n![rofi no fzf](rofi-no-fzf.png)\n\nWith:\n\n![rofi fzf](rofi-fzf.png)\n\n\n## Initial Plugin support\n\n> This feature is still in beta stage.\n\nIt is now possible to add custom mode via C plugins. This is allows interactive\nmodi to be added to rofi.  For example it is possible to have `top` (display\nlinux processes) mode:\n\n![rofi top](rofi-top.png)\n\nThis mode allows sorting of the result on different keys (cpu usage, memory,\netc.) to be selected, programs to be killed and refreshes the results every 2\nseconds.\n\n\nSee [here](https://gitcrate.org/qtools/rofi-top).\n\n## Configuration File\n\n> This feature is in alpha stage.\n\nThe new theme format can now (as an alpha) feature be used to set rofi's\nconfiguration. In the future, when we add wayland support, we want to get rid of\nthe current Xresources (X11) based configuration format.  You can see how this\nwould look using: `rofi -dump-config`.\n\n## Detailed Changelog\n\n* Improved error messages\n  * Theme parsing.\n  * Keybinding. Duplicate bindings will now be reported.\n  * Invalid commandline options.\n  * Etc.\n* Customizable highlight, allowing underline, strikethrough, italic, bold, small\n  caps and the color to be set.\n* Give up when keyboard is not grabbed in first 5 seconds.\n* Improve manpage\n    * rofi (1)\n    * rofi-themes (5)\n* Super-{1..10} hotkeys for selecting the first 10 rows.\n* Allow x-align/y-align on textbox.\n* Support matching bangs on multiple characters in combi mode. (#542)\n* Set WM_CLASS (#549)\n* Async pre-read 25 rows for improving user experience. (#550)\n* Improve handling in floating window manager by always setting window size.\n* DRun speedups.\n* Make lazy-grab default.\n* Remove extra layer in textbox. (#553)\n* Ignore fonts that result in a family name or size 0. (#554)\n* [Combi] Allow bang to match multiple modes. (#552)\n* Add detection of window manager and work around quirks.\n* Support dynamic plugins.\n* DMENU tty detection.\n* Support for icons in drun, combi and window mode.\n* Startup notification of launched application support.\n* Meson support.\n* Fuzzy matching with fzf based sorting algorithm.\n* Auto-detect DPI.\n* Set cursor at the end of the input field. (#662)\n* Meson support (thx to SardemFF7).\n* [Script] parse the command as if it was commandline. (#650)\n* Don't enable asan by meson. (#642)\n* Allow text widgets to be added in theme and string to be set.\n* [Dmenu] Support the -w flag.\n* Allow window (via window id) to be location for rofi window.\n* [Dmenu] Allow multi-select mode in `-no-custom` mode.\n* Flex/Bison based parser for new theme format.\n* Meson build support.\n* Initial plugin support, exporting of pkg-config file for rofi.\n* Improved positioning support for placing window on monitor.\n* Allow rofi to be placed above window based on window id.\n* Support different font per textbox.\n  * Keep cache of previous used fonts.\n"
  },
  {
    "path": "releasenotes/1.5.0/release-1.5.0.markdown",
    "content": "# V1.5.0: The Hoff uses it.\n\nAfter the last release turned out to be fairly large we are hopefully back to more regular, smaller releases.\nThis release focuses on squashing some bugs and hopefully improving the user experience.\nNevertheless this release also includes some new features.\n\nBig thanks to [SardemFF7](https://www.sardemff7.net/), without whose help and contributions this release would not have been possible.\n\n\n## New features\n\n### Specify matching field\n\nWhat field rofi should match on the drun view has been a source of [long discussions](https://github.com/DaveDavenport/rofi/pull/690),\nwhich resulted in new options to specify, which fields rofi should match against in either drun or window mode.\n\n`-drun-match-fields` *field1*,*field2*,...\n\nWhen using drun, match only with the specified Desktop entry fields.\nThe different fields are:\n\n* **name**: the application's name\n* **generic**: the application's generic name\n* **exec**: the application's executable\n* **categories**: the application's categories\n* **comment**: the application comment\n* **all**: all of the above\n\n    Default: *name,generic,exec,categories*\n\n`-window-match-fields` *field1*,*field2*,...\n\nWhen using window mode, match only with the specified fields.\nThe different fields are:\n\n* **title**: window's title\n* **class**: window's class\n* **role**: window's role\n* **name**: window's name\n* **desktop**: window's current desktop\n* **all**: all of the above\n\nDefault: *all*\n\n### Pass extra properties in script mode\n\nTo further improve script mode, support for passing properties has been added.\nYou can now set the `prompt`, a `message` or use `markup` and `active`/`urgent` colors from the script itself.\n\nE.g. to set the prompt from a bash mode script:\n\n```bash\necho -en \"\\x00prompt\\x1ftesting\\n\"\n```\n\nOr to mark the first 4 rows urgent and add a message:\n```bash\necho -en \"\\x00urgent\\x1f0-3\\n\"\necho -en \"\\0message\\x1fSpecial <b>bold</b> message\\n\"\n```\n\nThe `urgent` and `active` syntax is identical to the dmenu command-line argument.\n\n### Negated matching\n\nThe matching engine has been extended. It’s now possible to negate parts of the query. Searching for `deconz -sh` will list all\nfields that match `deconz` but do not contain `sh`.\n\n![match](rofi-match.png)\n\n![match negated](rofi-neg-match.png)\n\n### Hashtag rofi?\n\nIn themes the '#' prefix before the element name is now optional.\nAs well as not being needed, it made the multi-selector look weird.\n\nExample:\n\n```css\nentry,prompt {\n    background-color: DarkRed;\n    text-color:       White;\n}\n```\n\n## Backward incompatible changes\n\n### Mouse bindings\n\nMouse button and scroll bindings are now separated and naming has changed.\n\nFor the 3 base buttons:\n\n- `Mouse1` is now `MousePrimary`\n- `Mouse2` is now `MouseMiddle`\n- `Mouse3` is now `MouseSecondary`\n\nFor the scroll wheel:\n\n- `Mouse4` is now `ScrollUp`\n- `Mouse5` is now `ScrollDown`\n- `Mouse6` is now `ScrollLeft`\n- `Mouse7` is now `ScrollRight`\n\nFor extra buttons:\n\n- `Mouse8` is now `MouseBack`\n- `Mouse9` is now `MouseForward`\n- Above 10, you have to use the platform-specific `MouseExtra<number>` (replace `<number>`).\n\n## Bug fixes\n\n### Prompt colon\n\nThis is a controversial one, abeing the cause of heated [discussions](https://github.com/DaveDavenport/rofi/issues/637) in the past.\nThe prompt string of rofi is now left unmodified. Themes, like the default theme, can re-add the colon if desired.\n\n```css\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n}\n```\n\nResults in:\n\n![rofi colon](rofi-colon.png)\n\n### History size\n\nBy frequent request, you can now tweak the size of the history each modi keeps. While not recommended to change it as it\ncan cause performance issues, this allows power users to tweak it to their liking.\n\n```\nrofi.max-history-size: 500\n```\n\n## Full Changelog\n - [Theme] Accept integer notation for double properties. (#752)\n - [View] Theme textboxes are vertically sized and horizontal wrapped. (#754)\n - Rofi 1.4.2 doesn't capture ←, ↑, →, ↓ binding to keys to work in combination with Mode_switch (#744)\n - Add konsole to list of sensible terminals. (#739)\n - Allow drun to filter based on comment field. (#733)\n - Add prompt widget to default theme.\n - Add manpage for rofi-theme-selector.\n - Dump theme without # prefix and separator .\n - Fix issue with xnomad and -4 placing. (#683)\n - DRun obey OnlyShowIn and NotShowIn properties.\n - Store default theme in rofi binary using GResources.\n - Add extra margin between prompt and entry.\n - Remove colon from prompt. (#637)\n - Add support for passing extra properties in script mode.\n - Better error message on invalid argb syntax.\n - Fix default theme border.\n - Make '#' in the parser optional.\n - Update themes.\n - Add -drun/window-match-fields option (thx to Askrenteam) for drun/window menu. (#690/#656)\n - Implement negated match. (#665)\n - Fix parsing of non-existing fields. (#700)\n - rofi-theme-selector fixes.\n - Fix spelling error (thx to jmkjaer)\n - Fix test on i686/arm. (#692)\n - Fix error in theme manpage. (#686)\n - Allow history size to be specified. (#613)\n - Fix drun history implementation. (#579)\n - Add gentoo install instruction. (#685)\n"
  },
  {
    "path": "releasenotes/1.5.2/release-1.5.2.markdown",
    "content": "# 1.5.2: Procrastination in progress\n\nRofi 1.5.2 is another bug-fix release in the 1.5 series.\n\n\n## Fix border drawing\n\nIssue: #792, #783\n\nThere turned out to be a bug in how borders are drawn. It would overlap parts of the border on corners, screwing up\ntransparency.\n\n![broken border](border-issue.png)\n\nThis is now fixed.\n\n## Improve Icon handling\n\nIssue: #860\n\nSeveral bugs around Icon handling have been fixed:\n\n* Failing to load multiple (identical icons) on initial load.\n* Preload user-set icon theme.\n* Use the common threadpool in rofi for the icon fetching, instead of spawning a custom one.\n\n\n## New sort syntax\n\nBecause of all the changes to the sorting methods in rofi, the command-line options for it where very confusing.\nTo fix this they have been changed.\n\nThe `sort` option is now used to enable/disable sorting. (This can also be changed at run-time using the hotkey)\n\nThe `sorting-method` allows you to set the sorting method. Currently it supports **normal** (levenshtein) and **fzf**.\n\n## Documentation updates\n\nIssue: #879, #867, #837, #831, #804\n\nThanks to all the people highlighting or providing fixes to the documentation.\n\n## Improving the ssh known hosts file parser\n\nIssue: #820\n\nThe original known hosts parser was very limited. The parser has been extended to a bit more robust.\n\n## Additions\n\nFor some reason I can never make a release without adding more features to it. (Feature creep?).\n\n### Option to change the negate character\n\nIssue: #877\n\nThe option to negate a query: `foo -bar` e.g. search for all items matching `foo` but not `bar` caused a lot of\nconfusion. It seems people often use rofi to also add arguments to applications (that start with a -).\n\nTo help with this, the negate character (`-`) can be changed, or disabled.\n\nTo disable:\n\n```\nrofi -matching-negate-char '\\0'\n```\n\n\n### Modify the DRUN display string\n\nIssue: #858\n\nAn often requested feature is the ability to change the display string for the drun modi.\nThe `-drun-display-format` option is added that allows just this.\n\n> -drun-display-format\n>\n> The format string for the drun dialog:\n> * name: the application's name\n> * generic: the application's generic name\n> * exec: the application's executable\n> * categories: the application's categories\n> * comment: the application comment\n>\n> Default: {name} [({generic})]\n\nItems between `[]` are only displayed when the field within is set. So in the above example, the `()` are omitted when\n`{generic}` is not set.\n\n\n### Theme format now supports environment variables\n\nYou can use environment variables as part of your theme/configuration file property value.\nEnvironment variables start with `$` and the name is surrounded by `{}`.\nSo to query the environment `FOO` you can do:\n\n```css\n#window {\n    background: ${FOO};\n}\n```\n\nThe environment is then parsed as a normal value.\n"
  },
  {
    "path": "releasenotes/1.5.3/release-1.5.3.markdown",
    "content": "# 1.5.3: Time delayed progress\n\nRofi 1.5.3 is another bug-fix release in the 1.5 series.\n\nThere is one breaking change in the theme naming and there are a few small new features (tweaks) in this release.\n\n## Sidebar renamed to mode-switcher\n\nThe selection buttons to select between the different modi was still called `sidebar` a remnant from the past.\nThis has now been renamed to `mode-switcher`.\n\n## Icons in dmenu\n\nJust like in window,drun and script modi you can add icons to the list in dmenu mode.\n\nThe syntax is similar to the script modi:\n\n```bash\necho -en \"Firefox\\0icon\\x1ffirefox\\ngimp\\0icon\\x1fgimp\" | rofi -dmenu -no-config -show-icons\n```\n\n![dmenu icons](rofi-dmenu-icons.png)\n\n\nThe entries are separated by a `\\n` newline (normal dmenu behaviour).\nThe extra parameters can be added after a `\\0` null character, the key and value are separated by a `\\x1f` unit\nseparator character.\n\n\n## Ellipsizing listview entries\n\nIf you have very long entries in your view that get ellipsized (cut off at the end indicated by ...) you can now select,\nat runtime, where they are cut off (start, middle or end).\n\nYou cycle through the options with the `alt+.` keybinding.\n\nStart:\n\n![dmenu ellipsize](rofi-ellipsize-start.png)\n\n\nMiddle:\n\n![dmenu ellipsize](rofi-ellipsize-middle.png)\n\n\nEnd:\n\n![dmenu ellipsize](rofi-ellipsize-end.png)\n\n\n## Full Changelog\n\nThe full list of fixes and updates:\n\n* Update manpage with missing entry. (#937)\n* Rename sidebar widget to mode-switcher and allow configuration from theme.\n* Timing: Moving timing output to glib debug system.\n* SSH: Fix unitialized variable issue.\n* SSH: resolve ':' conflict in history entries.\n* SSH: be case-insensitive when parsing keywords.\n* RASI Lexer: Fix nested () in variable default field.\n* USABILITY: When mode not found, show in gui not just on commandline.\n* ICON: Allow aligning image in icon widget.\n* Meson build system: cleanups and improvements.\n* Meson build system: add documentation (#943)\n* Window: Fix default formatting and remove (invalid) deprecation warning.\n* DMenu: Add support for showing icons infront of displayed list.\n* Overlay: Fix overlay widget to correctly integrate in new theme format.\n* Update libnkutils, libgwater.\n* DMENU: Add format option to strip pango markup from return value.\n* ListView: allow user to change ellipsizing displayed value at run-time.\n"
  },
  {
    "path": "releasenotes/1.6.0/release-1.6.0.markdown",
    "content": "# 1.6.0: The Masked Launcher\n\nMore then 2 years after the 1.5.0 release and a year after 1.5.4, we present rofi 1.6.0. This release\nis again focusses bug-fixing and improving the experience for themers and\nscript developers. The script mode has been extended with many small requested tweaks to get it more\non par with dmenu mode. For themers the listview has been made more flexible, allowing more fancy themes,\nfor examples mimicking Gnomes application launcher or [albert](https://github.com/albertlauncher/albert).\n\nBig thanks to [SardemFF7](https://www.sardemff7.net/) and all the other\ncontributors, without their support and contributions this release would not\nhave been possible.\n\n\n## Script mode\n\nRofi now communicates some information back to the script using environment variables.\nThe most important one, is `ROFI_RETV`, this is equal to the return value in dmenu mode.\nIt can have the following values:\n\n * **0**: Initial call of script.\n * **1**: Selected an entry.\n * **2**: Selected a custom entry.\n * **10-28**: Custom keybinding 1-19\n\n\nTo fully read up on all features of script mode, there is now a `rofi-script(5)` manpage.\n\nSome of the new features are:\n\n * Search invisible text\n * Pass extra information back on selection\n * Support for a custom delimiter\n * Support for dmenus no-custom option\n * Detect if launched from rofi\n\n\nTo test some of the features:\n\n```bash\n#!/usr/bin/env bash\n\nif [ -z \"${ROFI_OUTSIDE}\" ]\nthen\n    echo \"run this script in rofi\".\n    exit\nfi\n\necho -en \"\\x00no-custom\\x1ftrue\\n\"\necho -en \"${ROFI_RETV}\\x00icon\\x1ffirefox\\x1finfo\\x1ftest\\n\"\n\nif [ -n \"${ROFI_INFO}\" ]\nthen\n    echo \"my info: ${ROFI_INFO} \"\nfi\n```\n\n\n## Theme\n\nThere have been a set of tweaks to the theme format, making it more flexible and hopefully more themer-friendly.\n\n\n### Listview flexibility\n\nThis is one of the biggest change, instead of the listview having a hacked\ntextbox as elements. It now re-uses existing widgets like box, icon and\ntextbox.  This way you can re-structure how it looks. For example put the icon\nabove the text.\n\n\n![Icons](./icons.png)\n\nWith theme:\n\n```css\nelement {\n  orientation: vertical;\n}\n```\n\nThis will make the box `element` put `element-icon` and `element-text` in a vertical list.\n\nor change the ordering to show icon on the right:\n\n```css\nelement {\n  children: [element-text, element-icon];\n}\n```\n\n![Icons vertical](./icons2.png)\n\n\n![icon warning](./warning.png)\nThis causes a breaking change for themes, to modify the highlighting, this should be set to `element-text`.\nOr inherited. `element-text { highlight: inherit; }`.\n\n### Calculation support in theme format.\n\nRofi adds CSS like calculations in the CSS format for distances.\nYou can now set the width of the window to the screen width minus a 10 pixels.\n\n```css\nwindow {\n    width: calc(100% - 10px);\n}\n```\n\nIt supports: `-`, `+`, `/`, `*` and `%` operators and they should be surrounded by whitespace.\n\n\n### Initial media support\n\nThis is a very initial implementation of CSS like `@media` support. This allows you to modify the theme\nbased on screen size or ratio.\n\nWe currently support: minimum width, minimum height, maximum width, maximum\nheight, monitor id, minimum aspect ratio or maximum aspect ratio.\n\n\nFor example, go to fullscreen mode on screens smaller then full HD:\n\n```\n@media (max-width: 1920 ) {\n  window {\n    fullscreen: true;\n  }\n}\n```\n\n\n## List of Changes\n\n* Add `themes/` directory in the users rofi config directory to the theme search path. (#1001)\n* Split listview element into box widget holding icon and textbox. Supporting more dynamic themes. (#949)\n* Fix default theme.\n* Add -upgrade-config option.\n* Add `ROFI_PLUGIN_PATH` variable.\n* Add check for running rofi inside a Script mode.\n* Remove gnome-terminal from rofi-sensible-terminal (#1074)\n* Set window title based on mode name. (#969)\n* Subpixel rendering workaround. (#303)\n* Support character type in configuration {} block . (#1131)\n* Use `XDG_CONFIG_DIRS` (#1133)\n* [Box] Bug fix update propagation.\n* [Build] Fix meson build with meson 0.55.\n* [DMenu] Add `-keep-right` flag. (#1089)\n* [DMenu] Don't match markup when filtering. (#579,#1128)\n* [DRUN] Support Type=Link (#1166)\n* [DRun] Add % to escape variable.\n* [DRun] Add an optional cache for desktop files. (#1040)\n* [DRun] Add keywords as default match item. (#1061)\n* [DRun] Don't run custom commands.\n* [DRun] Match keywords field.\n* [DRun] Only show selected categories. (#817)\n* [Dmenu|Script] Add non-selectable entries. (#1024)\n* [Doc] Update documentation.\n* [IconFetcher] Add jpeg support.\n* [Icon] Set default size to 1.2 CH.\n* [Icon] support distance for size.\n* [Listview] Add widget to show keybinding index. (#1050)\n* [Listview] Fix distribution of remaining space.\n* [Listview] Fix left-to-right scrolling. (#1028)\n* [Listview] Fix updating elements. (#1032)\n* [Matching] Make Fuzzy matching non greedy.\n* [Script] Add delimiter option. (#1041)\n* [Script] Add environment variable indicating state.\n* [Script] Add extra matchign field (meta). (#1052)\n* [Script] Add info option, hidden field that gets passed to script via `ROFI_INFO` environment.\n* [Script] Add no-custom option.\n* [Textbox] Add cursor blinking option.\n* [Textbox] Add placeholder. (#1020)\n* [Theme] Add `calc()` support. (#1105)\n* [Theme] Add alpha channel to highlight color. (#1033)\n* [Theme] Add sidebar as mode-switcher alias.\n* [Theme] Add some initial @media support. (#893)\n* [Theme] Support buttons in the UI.\n* [View] Add two widgets. One showing number of rows, other number of filtered rows. (#1026)\n* [Window] Add window thumbnail option.\n* [Window] Remove arbitrary # window limit. (#1047)\n* [Window] check buffer overflow.\n"
  },
  {
    "path": "releasenotes/1.6.1/release-1.6.1.markdown",
    "content": "# 1.6.1: Tortoise Power\n\nRofi 1.6.1 is another bug-fix release in the 1.6 series.\nThis release fixes a few issues with 1.6.0, most important the crash with drun-cache and\nresolving some issues that the default theme had on some systems.\nThere are a few minor new features introduced.\n\n\n## Theme: min/max and nested media support\n\nTo make themes more adoptable to different setups, `@media` statements can now be nested and support for min/max\noperation in `calc()` has been added.\n\n## FileBrowser\n\nThe file-browser plugin is now integrated in rofi.\n\n![File Browser](filebrowser.png)\n\n\n## ChangeLog\n   - Use GdkPixbuf for Icon parsing.\n   - Add FileBrowser to default mode.\n   - Fix parsing dicts in config file (with \" in middle of string.)\n   - Add -normalize-match option, that tries to o match ö, é match e. (#1119)\n   - [Theme] Add min/max operator support to calc() (#1172)\n   - Show error message and return to list instead of closing (#1187)\n   - [Theme] Add nested media support. (#1189)\n   - [Textbox] Try to fix estimated font height. (#1190)\n   - [DRun] Fix broken caching mechanism.\n"
  },
  {
    "path": "releasenotes/1.7.0/release-1.7.0.markdown",
    "content": "# 1.7.0: Iggy 2024\n\n![Iggy](./iggy.jpg)\n\nRofi 1.7.0 is another bug-fix release that also removes a lot of deprecated features.   One of the biggest changes is\nthe removal of the (deprecated) xresources based configuration setup. With this removal, also a lot of hack-ish code has\nbeen removed that tried to patch old config setups.  While the deprecation might be frustrating for people who have not\nyet converted to the new format, I hope for some understanding. Even though this move might not be popular, the\ndeprecation in previous releases and consequential removal of these options is needed for two reasons.\nThe most important one is to keep rofi maintainable and secondary to open possibility to overhaul the config system in\nthe future and with that fixing some long standing bugs and add new options that\nwhere hindered by the almost 10 year old system, the new system has been around for more than 4 years.\n\nBeside mostly bug-fixes and removal of deprecated options, we also improved the theming and added features to help in\nsome of the more 'off-script' use of rofi.\n\nThis release was made possible by many contributors, see below for a full list. Big thanks again to SardemFF7 and\nTonCherAmi.\n\n\n## Default theme loading\n\nIn older version of **rofi** the default theme was (almost) always loaded based on some unclear rules, sometimes \nsome random patch code was loaded and sometimes no theme was loaded before loading another theme.\n\nThe current version of rofi this is hopefully more logic.  It loads the default\ntheme by default using the default configuration. (Can be disabled by `-no-default-config`).\nUsing `-theme`, or `@theme` primitive will discard the theme completely.\n\nSo the below css completely removes the default theme, and loads `iggy`.\n\n```css\nconfiguration {\n\n\n}\n\n@theme \"iggy\"\n\nelement {\n    children: [element-icon, element-text];\n}\n```\n\n## File Browser\n\nTonCherAmi made several very nice usability improvements to the file-browser. His changes allow you to define sorting\nand ordering of the entries and changing the default start directory.\n\nThese options can be set using the new 'nested' configuration format that we are testing in rofi:\n\n```css\nconfiguration {\n   filebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /**\n        * Sorting method. Can be set to:\n        *   - \"name\"\n        *   - \"mtime\" (modification time)\n        *   - \"atime\" (access time)\n        *   - \"ctime\" (change time)\n        */\n      sorting-method: \"name\";\n      /** Group directories before files. */\n      directories-first: true;\n   }\n}\n```\n\n\n## File Completion\n\nIn rofi 1.7.0 a long awaited patch I wrote many years ago landed into the rofi.\nThis patch adds some basic completion support by chaining modi. Currently it\nonly supports chaining the FileBrowser mode. This allows you to launch an\napplication with a file as argument.  This is currently supported in the Run\nand the DRun modi by pressing the `Control-l` keybinding.  For the Run mode it\nwill add it as first argument, in DRun it only works if the Desktop file\nindicates support for this.\n\n![completer](./complete.gif)\n\nThis is not the final implementation, but a first investigation in how to\nadd/extend this feature. Ideally you can have multiple completers (including\ncustom ones) you can choose from.\n\n\n## Timeout actions\n\nYou can now configure an action to be taken when rofi has not been interacted\nwith for a certain amount of seconds. You can specify a keybinding to trigger\nafter X seconds.\n\nThis option can be set using the new 'nested' configuration format that we are\ntesting in rofi:\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n}\n```\n\nThis setting will close rofi after 15 seconds of no interaction.\n\n```css\nconfiguration {\n  timeout {\n      delay:  5;\n      action: \"kb-accept\";\n  }\n}\n```\nThis setting will accept the current selection after 5 seconds of no\ninteraction.\n\n## Background image and gradients\n\nTo improve theming the `background-image` property was added with support for\nsetting images `url()` or a gradient `linear-gradient()`.\n\n```css\nwindow {\n    background-image: url(\"/tmp/i3.png\", both);\n}\nelement {\n    children: [element-icon, element-text];\n    background-image: linear-gradient(to bottom, black/20%, white/20%, black/10%);\n}\n```\n\nThe below screenshot shows both background image and gradients.\n\n![background image](./background-image.png)\n\nOr a more subtle change is the gradient on the tabs here:\n\n![iggy-theme](./iggy-theme.png)\n\n\n## Clickable button and icons\n\n```css\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\n```css\nbutton-paste {\n    expand: false;\n    content: \"My Clickable Message\";\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\n```\n\nThe screenshot below shows a non-squared image and clickable buttons (the close icon in the top right)\n\n![rofi icons](./rofi-icons.png)\n\n\n# Changelog\n\n* ADD: -steal-focus option.\n\nExplicitly steal focus from from the current window and restore it on closing.\nEnabling this might break the window switching mode.\n\n* ADD: [Config] Add nested configuration option support.\n\nAllow for nested configuration options, this allows for options to be grouped.\n\n```css\nconfiguration {\n  timeout {\n      delay:  15;\n      action: \"kb-cancel\";\n  }\n  combi {\n    display-name: \"Combi\";\n  }\n}\n\n```\n\n\n* ADD: [Config] Support for handling dynamic config options.\n\nA quick work-around for handling old-style dynamic options. This should be resolved when all options are\nconverted to the new (internal) config system.\n\n* ADD: [DRun] Add fallback icon option.\nThis option allows you to set a fallback icon from applications.\n```css\nconfiguration {\n  application-fallback-icon: \"my-icon\";\n}\n```\n\n* ADD: [IconFetcher] Find images shipped with the theme.\n\nIf you have an icon widget you can specify an image that exists in the theme directory.\n```css\n\nwindow {\n  background-image: url(\"iggy.jpg\", width);\n}\n```\n\n* ADD: [DRun] Add support for passing file (using file-browser) completer for desktop files that support his.\n\nSee above.\n\n* ADD: [DRun] Support for service files.\n\nSupport KDE service desktop files.\n\n* ADD: [FileBrowser] Allow setting startup directory (#1325)\n* ADD: [FileBrowser]: Add sorting-method. (#1340)\n* ADD: [FileBrowser] Add option to group directories ahead of files. (#1352)\n\nSee above.\n\n* ADD: [Filtering] Add prefix matching method. (#1237)\n\nThis matching method matches each entered word to start of words in the target\nentry.\n\n* ADD: [Icon] Add option to square the widget.\n\nBy default all icons are squared, this can now be disabled. The icon will\noccupy the actual space the image occupies.\n\n* ADD: [Icon|Button] Make action available on icon, button and keybinding name.\n\nSee above.\n\n* ADD: [KeyBinding] Add Ctrl-Shift-Enter option. (#874)\n\nThis combines the custom and alt keybinding. Allowing a custom command to be\nlaunched in terminal.\n\n* ADD: [ListView]-hover-select option. (#1234)\n\nAutomatically select the entry under the mouse cursor.\n\n* ADD: [Run] Add support for passing file (using file-browser) completer.\n\nSee above.\n\n* ADD: [Textbox] Allow theme to force markup on text widget.\n\nForce markup on text widgets.\n\n* ADD: [Theme] theme validation option. (`-rasi-validate`)\n* ADD: [View] Add support for user timeout and keybinding action.\n* ADD: [Widget] Add cursor property (#1313)\n\nAdd support for setting the mouse cursor on widgets.\nFor example the entry cursor on the textbox, or click hand cursor on the entry.\n\n```css\nelement,element-text,element-icon, button {\n    cursor: pointer;\n}\n\n```\n\n* ADD: [Widget] Add scaling option to background-image.\n\nAllows you to scale the `background-image` on width, height and both.\nSee above example.\n\n* ADD: [Widget] Add support background-image and lineair gradient option.\n\nSee above.\n\n* ADD: [Window] Add pango markup for window format (#1288)\n\nAllows you to use pango-markup in the window format option.\n\n\n* ADD: [Window] Allow rofi to stay open after closing window.\n\n```css\nconfiguration {\n  window {\n      close-on-delete: false;\n  }\n}\n\n```\n\n* FIX: [DSL] Move theme reset into grammar parser from lexer.\n\nGiven how the lexer and the grammar parser interact, the reset did not happen at\nthe right point in the parsing process, causing unexpected behaviour.\n\n* FIX: [Drun]: fix sorting on broken desktop files. (thanks to nick87720z)\n\nBroken desktop files could cause a rofi crash.\n\n* FIX: [File Browser]: Fix escaping of paths.\n\nFix opening files with special characters that needs to be escaped.\n\n* FIX: [ListView] Fix wrong subwidget name.\n\nFixes theming of `element-index`.\n\n* FIX: [Script] Don't enable custom keybindings by default.\n\nThe quick switch between modi was broken when on a script mode. This now by default works,\nunless the mode overrides this.\n\n* FIX: [TextBox] Fix height estimation.\n\nThis should fix themes that mix differently sized fonts.\n\n* FIX: [Theme] widget state and inherited properties. This should help fixing some old themes with changes from 1.6.1.\n\nAn old pre-1.6.1 rasi theme should work with the following section added:\n\n```css\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\n```\n\n* FIX: [Widget] Fix rendering of border and dashes. (Thanks to nick87720z)\n\nThis fixes the long broken feature of dashed borders.\n\n```css\nmessage {\n    padding:      1px ;\n    border-color: var(separatorcolor);\n    border:       2px dash 0px 0px ;\n}\n\n```\n\n* FIX: [Build] Fix CI.\n\n* FIX: [Theme] Discard old theme, when explicitly passing one on command line.\n\nIn previous version there was a bug when passing `-theme` on commandline did not discard old theme.\nThis caused problems loading themes (as it merged two themes instead of loading them).\n\nTo get old behaviour on commandline do:\n\n```bash\n\nrofi -theme-str '@import \"mytheme\"' -show drun\n````\n\n* REMOVE: -dump-xresources\n* REMOVE: -fullscreen\n* REMOVE: -show-match\n* REMOVE: Old xresources based configuration file.\n* REMOVE: fake transparency/background option, part of theme now.\n* REMOVE: xresources parsing via Xserver\n* Remove: [Theme] Remove backwards compatiblity hack.\n* DOC: Update changes to manpages\n\n\n# Thanks\n\nBig thanks to:\n\n* Morgane Glidic\n* a1346054\n* Ian C\n* TonCherAmi\n* nick87720z\n* Markus Grab\n* Zachary Freed\n* nickofolas\n* unisgn\n* Jas\n* rahulaggarwal965\n* Awal Garg\n* Eduard Lucena\n* Lars Wendler\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.1/release-1.7.1.markdown",
    "content": "# 1.7.1: Turtley amazing!\n\nThis release focusses on fixing bugs found in 1.7.0. The most important ones\nare fixing sizing bug, fix nested media statements and broken close-on-delete.\nThere are a few new features to help themeing: We now support\n`env(ENV,default)` statement and when dumping a theme theme-names are resolved\n(f.e. `green`, `lightblue`, etc.).\n\nThanks to everybody reporting bugs, providing patches that made this release possible.\n\nFor a more complete list of changes see below.\n\n# Changelog\n\n* [Theme] Fix highlight with only theme.\n* Updated documentation and landing page (Thanks to RaZ0rr-Two)\n* [Combi] Fix nesting combi modi (#1510)\n* [DMenu] Fix crash dmenu mode when no entry is available. (#1504)\n* [Run|Drun] Only initialize file-completer on first use.\n* [FileBrowser] Reduce number of re-allocs.\n* [Readme] Remove generating readme.html for dist.\n* [Dmenu] Fix uninitialized memory (non-selectable)\n* [FileBrowser] Try to convert invalid encoded text. (#1471)\n* [FileBrowser] Don't crash on invalid file filenames. (#1471)\n* [Theme] print known colors as its color name.\n* [CMD] If failed to convert commandline to new option, do not stop. (#1425)\n* [Theme] Fix parsing of nested media blocks. (#1442)\n* [Widgets] Fix sizing logic widgets. (#1437)\n* [Window] Try to fix auto-sizing of desktop names for non-i3 desktops. (#1439)\n* [Window] Fix broken close-on-delete. (#1421)\n* [Listview] Correctly check if selected item is highlighted. (#1423)\n* [Entry] Allow action to be taken on input change. (#1405)\n* [Theme] Don't truncate double values. (#1419)\n* [Grammar] Add support for env(ENV,default).\n* [Documentation] documentation fixes.\n* [Theme] fix dmenu theme ( #1396).\n\n# Thanks\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n* Iggy\n* RaZ0rr-Two\n* Morgane Glidic\n* Danny Colin\n* Tuure Piitulainen\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.2/release-1.7.2.markdown",
    "content": "# 1.7.2: Shellebrations! \n\nA quick in between release, a bug got fixed that caused configurations not working any more in theme files.\nWhile this is the desired behaviour, this release reverts it to avoid breaking to many setups.\n\n# Changelog\n\nv1.7.2:\n   - [Build] Fix building without window mode enabled.\n   - [Config] Do not print out the 'theme' field in configuration on dump.\n   - [CI] test window mode less build.\n   - Allow configuration block in theme again.\n\n# Thanks\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n* Iggy\n* Morgane Glidic\n* Danny Colin\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.3/release-1.7.3.markdown",
    "content": "# 1.7.3: Sturtled!\n\nA small intermediate release with a few fixes, mostly in documentation and two great additions by Jakub Jiruta:\n\n * An option to customize the combi mode display format. \n * To possibility to set tab stops on listview and entry boxes.\n\n# Changelog\n\nv1.7.3:\n   - [Help] Print out the parsed config/theme files in -help output.\n   - [Keybindings] Fix keybindings being modified by -theme-str\n   - [Doc] Add rofi-dmenu manpage.\n   - [XCB] Cache lookup of monitor.\n   - Add -replace option (#568)\n   - Fix memory leak.\n   - [1566] Add extra debug for resolving monitors.\n   - [Theme] Add round,floor,ceil function in @calc (#1569)\n   - [Doc] Explain icon lookup.\n   - [Combi] Add -combi-display-format (#1570) (thanks to Jakub)\n   - [Theme] Expand list type ([]) for more data types.\n   - [Theme] Add support for tab-stops on textbox. (#1571) (thanks to Jakub)\n   - [Theme] Testing direct access to widgets via cmdline option (-theme+widget+property value)\n\n# Thanks\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n* Iggy\n* Morgane Glidic\n* Danny Colin\n* Jakub Jirutka\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.4/release-1.7.4.markdown",
    "content": "# 1.7.4: Preshellected Optimizations\n\nAnother maintenance and small features expansion release. A lot of small\nannoyances have been fixed and ignored errors are now more visually flagged to\nthe user. In the past typos in the theme could result into broken themes\nwithout any warning to the user (except in debug mode), if an unknown link is\nfound it will now throw an error. To help the user find the right\ndocumentation, the manpages are further split up into sub-pages and are\nexpanded\n\nWe now have:\n\n* rofi(1)\n* rofi-theme-selector(1)\n* rofi-keys(5)\n* rofi-theme(5)\n* rofi-debugging(5)\n* rofi-dmenu(5)\n* rofi-script(5)\n\nAnother improvement made that can have huge impact on the user-experience is a\nsignificant speedup in the async input reading of dmenu. It turned out glib's\nGInputStream async methods are very slow. On large input sets where it was\nsupposed to improve the user experience, it made it unusable. To resolve this a\ncustom implementation has been made. Background loading is now close to the\nsame speed as loading at start before displaying. A million item list is now\nnear instant. On very large lists, the instant filtering automatically changes\nto be postponed until the user stops typing. This severely reduces system load\nand interface blocking.\n\nA few long standing feature requests and bug reports have been implemented or fixed:\n\n* Listview flow. You can now change the flow in the listview from vertical first\n  to horizontal first. Making it mimic tables.\n\n```bash\nfor i in {1..90}; do echo $i; done | rofi -dmenu -no-config -theme-str 'listview { columns: 3; flow: vertical; }'\n```\n![Vertical](./vertical.png)\n\n```bash\nfor i in {1..90}; do echo $i; done | rofi -dmenu -no-config -theme-str 'listview { columns: 3; flow: horizontal; }'\n```\n![Horizontal](./horizontal.png)\n\n* You can set a custom fallback icon for each mode.\n\n```css\nconfiguration {\n  run,drun {\n    fallback-icon: \"application-x-addon\";\n  }\n}\n```\n\n* In dmenu mode (and script) you can now make (some) changes to the theme, for\n  example modifying the background color of the entry box.\n\n```bash\necho -en \"\\0theme\\x1felement-text { background-color: red;}\\n\"\n```\n\n* User scripts (for script mode) into `$XDG_CONFIG_HOME/rofi/scripts` directory\n  are automatically available in rofi.\n\n```bash\nrofi -h\n<snip>\nDetected user scripts:\n        • hc (/home/qball/.config/rofi/scripts/hc.sh)\n</snip>\n```\n\nThis script can now by shows by running `rofi -show hc`.\n\n* You can now render text as icons, this allows you to use glyphs icon fonts as\n  icons.\n\n```bash\necho -en \"testing\\0icon\\x1f<span color='green'>Test</span>\" | rofi -dmenu\n```\n\n* Hide listview when unfiltered. (#1079) \n\n```css\nlistview {\n    require-input: true;\n}\n```\n\n* You can now add a separate icon or textbox widget to the UI that displays the\n  current selected item. As an example see the included `sidebar-v2`.\n\n* A bug was fixed that caused problems with newer xkeyboard-config versions and\n  different keyboard layouts.\n\nBelow is a more complete list of changes:\n\n# Changelog\n\n* [Doc] Add `-config` to `-help` output. (#1665)\n* [Dmenu] Fix multi-select, use text as indicator.\n* [filebrowser] Fix building on Mac. (#1662,#1663)\n* [textbox] Implement text-transform option. (#1010)\n* [script] Add `new-selection` (#1064).\n* [Script] Add keep-selection flag that keeps the current selection. (#1064)\n* [Debug]  Add '-log' flag to redirect debug output to a file.\n* [XCB]    Try to deduce rotated monitors.\n* [Doc]    Add rofi-dmenu to 'See also' in rofi(1).\n* [Options] Mark offset(s) as deprecated.\n* [Modes] Support loading multiple icon sizes.\n* [View]  Add textbox|icon-current-entry widget.\n* [Doc]   Add ascii manpage to rofi-script(5).\n* [Script] Print user-scripts in -h\n* [Script] Look into $XDG_CONFIG_HOME/rofi/scripts/ for user scripts.\n* [Dmenu|Script] Allow (some) theme modification from script/dmenu.\n* [Textbox] Fix some pango alignment.\n* [FileBrowser] Bind 'kb-accept-custom-alt' to directory up.\n* [Build] Add desktop files as per complaint (rofi theme selector and rofi itself).\n* [Dmenu] Code cleanups.\n* [Themes] Remove broken themes.\n* [Modes] Allow fallback icon per mode. (#1633)\n* [View] Fix broken anchoring behaviour. (#1630)\n* [Rofi] Move error message on commandline to UI.\n* [Listview] Option to hide listview elements when not filtered. (#1622,#1079)\n* [DMenu] Speed up reading async in of large files from stdin.\n* [FileBrowser] Make accept-alt open folder if selected.\n* [Helper] Add XDG_DATA_DIRS to the theme search path. (#1619)\n* [Doc] Split up manpages and extend them with examples.\n* [Doc] Highlight use of `-dump-config` in config. (#1609)\n* [Config] Workaround for in data type passed to string option.\n* [Listview] Allow flow of elements to be set. (#1058)\n* [Script] Add data field that gets passed to next execution. (#1601)\n* Change modi to modes to avoid confusion.\n* [Theme] When links are unresolvable throw an error to the user.\n* [DMenu] Document the `display-columns` and `display-column-separator` option.\n* [Theme] Media now supports `enabled` that supports an environment variable.\n* [IconFetcher] Support rendering fonts as icon.\n* [xcb] Remove work-around to fix use with new xkeyboard-config (#1642)\n\n# Thanks\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n* Iggy\n* Morgane Glidic\n* Danny Colin\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.5/release-1.7.5.markdown",
    "content": "# 1.7.5:  We shell overcome\n\nA quick bug-fix release to fix 2 small issues.\n\n* In DMenu sync mode, the separator is left in the string.\n* On special crafted delayed input in dmenu it shows updates to the list very slow.\n  It now forces to push update (if there) every 1/10 of a second.\n* In the view some of the update/redraw policies are fixed to reduced the\n  perceived delay.\n\nThis makes it clear we need more people testing the development version to\ncatch these bugs. I only use a very limited set of features myself and do not\nhave the time nor energy to write and maintain a good automated test setup.\nThere was one in the past that tested some basic features by running rofi,\ninputting user input and validating output. But it was not reliable and\ndifficult to keep running.\n\n\n# Thanks\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n* Iggy\n* Morgane Glidic\n* Danny Colin\n\nApologies if I mistyped or missed anybody.\n"
  },
  {
    "path": "releasenotes/1.7.6/release-1.7.6.markdown",
    "content": "# 1.7.6: Traveling Time\n\n## Recursive file browser\n\nAn experimental file browser is introduced in this version.\nThis recursively scans through the users home directory (this is configurable) to find files.\nIt is designed to be asynchronous and very fast.\n\nThe following settings can be configured:\n\n```css\nconfiguration {\n   recursivebrowser {\n      /** Directory the file browser starts in. */\n      directory: \"/some/directory\";\n      /** return 1 on cancel. */\n      cancel‐returns‐1: true;\n      /** filter entries using regex */\n      filter‐regex: \"(.*cache.*|.*.o)\";\n      /** command */\n      command: \"xdg‐open\";\n   }\n}\n```\n\nA thumbnail generation mechanism is also supported if `-show-icons` is enabled.\nSee details and setup in the `rofi-thumbnails(5)` man page. Thanks to giomatfois62 for\nbringing this feature to life!\n\n## Copy to clipboard support\n\nAdd support to copy current selected item to clipboard.\nThe added `control-c` binding copies the current selection to the clipboard.\n\n**THIS ONLY WORKS WITH CLIPBOARD MANAGER!!!** Once rofi is closed, the data is\ngone!\n\n## Entry box history\n\nYou can now recall and move through previous queries by using\n`kb-entry-history-up` or 'kb-entry-history-down` keys. (`Control-Up`,\n`Control-Down`).\n\nThe following settings can be configured:\n\n```css\nconfiguration {\n    entry  {\n        max‐history: 30;\n    }\n}\n```\n\n## Fix calc\n\nThere was a non-parsable grammar in the 'calc' part of the language.\nThe % operator (modulo) overloaded with percent and could leave to statements\nhaving multiple valid but contradicting interpretations.\nTo resolve this the modulo operator is now `modulo`.\n\nSeveral smaller issues with the parser were also fixed in this patch.\n\n## Text and cursor outline\n\nThree new properties were added to textbox widgets to control text outline:\n\n* `text-outline` boolean to enable outlines\n* `text-outline-width` to control size\n* `text-outline-color` to control color\n\n![Outlines](./text-outline.png)\n\nOutlines can also be added to cursors, via similarly named\nproperties (`cursor-outline-*`).\n\n## Dependencies and packaging\n\nIn this version, we have bumped the minimal required versions of some\ndependencies to keep up with bugs and deprecations while staying compatible\nwith long-term supported distributions.\n\n* glib: 2.72 or newer\n* meson: 0.59.0 or newer\n\nThis roughly corresponds to Ubuntu 22.04 Jammy and Debian Bookworm.\n\nGenerated man pages were removed from the git repository and now require\n`pandoc` to build instead of `go-md2man`. If you compile from git, you\nwill now need to install `pandoc` to get the man pages.\n\nRelease tarballs still contain the files and can be installed without\nadditional tool.\n\n## Known issues\n\n* `new-selection` is not working for values exceeding the number of rows in previous run. (#2037)\n\n## Other smaller changes\n\n* new `.rasinc` extension for theme fragments included from other theme files\n* `-ellipsize-mode` mode option in dmenu mode can be set to `start`, `middle` or `end`\n  to control how long entries are ellipsized\n* `-list-keybindings` to print a summary of configured bindings\n* `-window-prefer-icon-theme` to force precedence of theme icons over applications'\n  custom ones (#1702)\n* `-placeholder-markup` to enable pango markup when rendering placeholder text (#1690)\n* `urgent` and `active` flags can be controlled for each row in dmenu and script\n  modes\n* `-transient-window-mode` to make rofi react like a modal dialog that is transient to\n  the currently focused window.\n* Fixing window coordinates for non-reparting window manager. (Thanks to Ortango #1969)\n* Fix failing decode of animated gif files. (Thanks to martinsifrar #1975)\n\n## Website\n\nThe current documentation is now also available online at:\n[https://davatorium.github.io/rofi/](https://davatorium.github.io/rofi/)\n\n# Thanks to\n\nBig thanks to everybody reporting issues.\nSpecial thanks goes to:\n\n  * a1346054\n  * aloispichler\n  * Amith Mohanan\n  * Christian Friedow\n  * cognitiond\n  * David Kosorin\n  * Dimitris Triantafyllidis\n  * duarm\n  * Fabian Winter\n  * giomatfois62\n  * Gutyina Gergő\n  * Jasper Lievisse Adriaanse\n  * Jorge\n  * martinsifrar\n  * Martin Weinelt\n  * Morgane Glidic\n  * Naïm Favier\n  * Nikita Zlobin\n  * nomoo\n  * notuxic\n  * Ortango\n  * Rasmus Steinke\n  * Tim Pope\n  * TonCherAmi\n  * vE5li\n  * Yuta Katayama\n  * Danny Colin\n  * xsy420\n\nApologies if I mistyped or missed anybody.\n\n# Changelog\n* [CI] Fix CI build for updated runner.\n* [DOC] Add mouse button names to documentation.\n* [Doc] Clarify documentation for User Script directory. (#2043)\n* [Build] Add shadow to build system. (#2042, #2036)\n* [Textbox] Use FontMetrics font height (if available) to get height\n* [Theme] Fixes recursion in double_inside\n* Try to support modifiers in XIM again (#2015)\n* [autoconf] Fix missing dependency.\n* Better XIM interaction by filtering modifiers (#2000)\n* Fix ime and enable build option (#1999)\n* [Autotools] Ship missing files for meson build\n* Fix some compiler warnings\n* #1995: Disable history in password mode, move disabling into create_view.\n* [config] Set filebrowser as default completer.\n* [WIP] xdg thumbnails fetching with fallback on mimetype icons (#1939)\n* Add -transient-window mode (#1988)\n* Fix scrolling for vertical layout with horizontal packing\n* Place continuous scroll center in middle column\n* [Script] Fix keep-selection add keep-filter\n* [RecursiveBrowser] Make implementation not recursive.\n* [xcb] Add border_width to window coordinates (#1969)\n* [IconFetcher] Don't check for extension for image file\n* [IconFetcher] Fix failing decode of animated GIFs. (#1975)\n* [Doc] Fix typos, thx to @Nickwiz\n* [Run] Don't re-quote history items.\n* [Modes] Remove dead code in mode implems (#1960)\n* [View] Work around GThreadPool 1 pointer bug.\n* Also fix typo in icon fetcher.\n* [Github] Bump checkout to v4\n* [Doc] Switch to pandoc and remove generated files (#1955)\n* [Build] Add missing dist files from libnkutils\n* [IconFetcher] Don't free on removal from thread-pool\n* Add an item-free method to the thread-pool\n* [Window] write code so clang-check does not complain about leak.\n* [script|dmenu] Add option to make row permanent. (#1952)\n* [run] fix missing doxygen and add explanation.\n* [Run] When passing raw entry, pass it unquoted to history (#1951)\n* Replace deprecated g_memdup by g_memdup2\n* Bump glib version to 2.72\n* [Build] Bump minimal meson version to 0.59.0 (#1947)\n* Fix compiler warnings in window mode.\n* Fix some compiler warnings.\n* [RUN] shell escape command before processing it further.\n* [DRun] Drun read url field from cache.\n* [Build] Reduce amount of warnings (#1944)\n* [View] Don't use xcb surface to render to png, but create surface.\n* [Box] When estimating height, set correct width on children (#1943)\n* [ThreadPool] Sort items in the queue based on priority\n* [Doc] Fix broken ``` guards.\n* [Doc] Remove reddit link from config.yml.\n* [Doc] Clarify in build instructions what release to use.\n* Add extra documentation issue template.\n* Fix typo in dynamic_themes.md (#1941)\n* [DOC] Add explanation to PATTERN of brackets (#1933)\n* [Doc] Update manpage to clarify meta property.\n* [View] On mode switch force refilter instead of queuing. (#1928)\n* [View] Allow float delay (#1926)\n* [View] Always forward motion to the grabbed widget first.\n* [IconFetcher] If last step fails to load icon, don't error out make warning\n* [Script] Update theme property clarification a bit.\n* [Script] Add clarification to theme property.\n* [Dmenu][Script] Add 'display' row option to override whats displayed.\n* [DRun] Allow url field to be searched and fix c/p error (#1914)\n* [DRUN] Add {url} to drun-display-format. (#1914)\n* [lexer] Add dmenu as enabled option for media type. (#1903)\n* [XCB] Make sure that window maker is 0 terminated before usage.\n  Thanks to Omar Polo and bsdmp\n* Fix text color when `cursor-color` is set (#1901)\n* [XCB] Try to be smarter with where mouse click started. (#1896)\n* [View|Textbox] cleanups to drawing code\n* Clip text with extents rectangle\n  Fonts are not ideal, some characters have mismatch between reported and\n  painted size.\n* [Rofi] Expand cache-dir (#1892)\n* Fix typos in dmenu docs (#1891)\n* Support single quotes for strings as in CSS\n* [Theme] Fix missing doxygen documentation\n* [Theme] Fix opening abs path if no/wrong extension (backward comp.)\n* [rofi-theme] fix typo\n* [Theme] Try to fix importing of theme.\n    - Fix the two place of resolving into one method.\n    - Do not accept file in CWD.\n    - Prefer file if it exists in same directory as parent file that\n      imported it.\n    (#1889)\n* script: Let script handle empty custom input\n* widget_draw: clean useless calls in corner drawing\n* Fix border segments stitch\n* Fix mm type in description\n* Remaining modi words in the code\n* Better descriptions for sort options group\n  It's unobvious from documentation, that sort only works against filtered menu.\n* update man pages without scripts\n* [Lexer] Print some more debug info on error. (#1865)\n* [Script] Set type on Mode object.\n* [window] Quick test of code scanning.\n* [ROFI] -e '-' reads from stdin\n* [ConfigParser] Don't pass commandline options with very long args.\n    This is a quick 'n dirty fix for this unexpected issue.\n    (#1855)\n* [Build] Fix autotools build system.\n* [Doc] Fix some missing/wrong doxygen headers.\n* Print window manager in -help output\n* Merging in the Recursive file browser.\n* Add wezterm to rofi-sensible-terminal (#1838)\n* [DRun] Add option to scan desktop directory for desktop files.\n* [IconFetcher] Fix small memory leak.\n* Small memory leaks fixed and other cleanups.\n* [MKDocs] Add logo\n* [DMenu] Fix row initial tab if non-first column is shown first. (#1834)\n* [Doc] Update theme manpage with remark-lint hints.\n* [Doc] More small markdown fixes.\n* [DOC] Update rofi-script update with remark-lint remarks.\n* Remove unneeded test and extra enforcement of 0 terminated buffer\n* [Doc] Update rofi.1.markdown with markdown fixes.\n* [DOC] update readme.md with remark-lint updates..\n* [DOC] Update INSTALL,md with remark-lint fixes.\n* [DOC] Add some remark markdown fixes.\n* Fix to pointless or's.\n* [UnitTest] Add more tests for environment parsing.\n* [Doc] Mention location of scripts in manpage.\n* Re-indent the code using clang-format\n* Fix typo in template.\n* Update issue template to include checkbox for version.\n* [Doc] Re-generate manpage\n* docs: element children theming (#1818)\n* Add support for adding textbox widgets to listview elements (#1792)\n* [Textbox] cairo_save/restore does not store path.\n    Fix by moving cairo_move_to to after blink.\n    Also fix drawing outline.\n* More Unicode normalization with `-normalize-match` (#1813)\n    Normalize the string to a fully decomposed form, then filter out mark/accent characters.\n* #1802: Calc broken fix (#1803)\n    * [Theme] First move to double internal calculations.\n    * [Theme] Allow float numbers.\n    * [Theme] Fix unary - and tighten the grammar parser.\n    * [Theme] Rename % to modulo to fix compiler.\n    * [Theme] Dump right modulo syntax.\n    * [Test] add missing end_test\n    * [Grammar] Allow negative numbers as property value\n* [Dmenu] Small fix that disabled async mode when multi-select is enabled.\n* [View] Fix wrong bitmask checking. (& not |)\n* [rofi-theme-selector] prepend newline before specifying new theme (#1791)\n    * [rofi-theme-selector] prepend newline before specifying new theme\n      If the EOF is not a newline, new theme setting will fail.\n    * make sed substitution more readable\n    * simplify sed substitution\n* [MKDocs] Try to fix link.\n* [MKDocs] Add downloads to side menu\n* [MKDocs] Add a download page.\n* [Script] Strip pango markup when matching rows (#1795)\n* [Doc] theme, spelling fix and more textual tweaks.\n* [Doc] More tweaks to get the formulation right.\n* [Doc] themes manpage, small textual improvement.\n* [Doc] Try to fix some markdown, themes.\n* [Doc] Try to clarify the children situation for the listview widget.\n* [EntryHistory] Disable entry history when dmenu password is set.\n* I785 (#1789)\n    * [Textbox] Add history to the entrybox.\n    * [Textbox] Add comments and move into sub functions.\n    * [doc] Add conflicting constraint section to manpage.\n    * [Script] Some small memory leak fixes.\n    * [Entry History] Add documentation.\n    (#785)\n* [doc] Add conflicting constraint section to manpage.\n* [mkdoc] add link to user scripts\n* [Textbox] Replace 'space' with a space (#1784)\n* draw text after cursor (#1777)\n* [Doc] Small tweak to markdown.\n* [Example] Small change in escaping for caday.\n* [Doc] Add manpage documentation for pango font string.\n* [MKDocs] Add dynamic theme guide.\n* [FileBrowser] Allow command to be overwritten\n* [theme] Small theme tweak.\n* [Theme] Add NO_IMAGE mode to theme.\n* [Themes] add fullscreen theme with preview part.\n* [window] When no window title set, handle this more gracefully\n* [DMenu|Script] Add per row urgent/active option.\n    Instead of having a global list of entries to highlight urgent/active,\n    you can now to it per row.\n* sed & realpath workaround for BSD and Darwin OS\n* [filebrowser] Add option to return 1 on cancel.  (#1732)\n* [Theme] Small tweak to fancy2 theme\n* [MKDocs] Link to rasi files in theme page.\n* [Themes] Add fancy2 theme.\n* [Themes] Add material theme\n* Fix header theme\n* [Helper] Quick fix for wrong dereference.\n* MKDoc website (#1772)\n    * Add initial documentation page using mkdocs\n    * Test action\n    * Add notes to mkdoc site.\n    * Add installation guide\n    * Add installation and config guide to mkdocs.\n    * Add installation manual\n    * Add image to main page\n    * [mkdocs] Add plugin guide.\n    * [mkdocs] Add plugin to main page and some small fixes.\n    * Add shipped themes page\n    * [actions] Also rebuild website on the next branch\n* [themes] don't use screenshot transparency in shipped themes\n* [IconFetcher] Fix for api change\n* [Theme] support rasinc for theme include files.\n* [listview] Don't calculate infinite rows on empty height. (#1769)\n* [Theme] Move some definitions header around for plugin.\n* [Textbox] Cursor goes over, not under. allow cursor outline.\n* [Textbox] Add text-outline to style\n* [Doc] Clarify documentation on `require-input` further.\n* make cursor more customizable by adding cursor-width and cursor-color (#1753)\n    * make cursor more customizable by adding cursor-width and cursor-color to the theme\n    * fix placeholder color\n    * add doc entry\n    * more documentation\n* [XIM] Fix an unitialized value problem.\n* [Doc] Add example run command with cgroup support (#1752)\n* [Build] Fix test building in makefile.\n* [Doc] Add documentation for new functions.\n* [Doc] Fix some missing docu.\n* [DMenu] Add -ellipsize-mode option.\n* [listview] Set ellipsize mode on creation of textbox\n  So if rows are added, they behave correctily. (#1746)\n* Disable imdkit by default\n* Build documentation (#1744)\n    * explain how to pass options to meson\n    * fix typo in INSTALL.md\n* [Build] Use built-in lto option.\n* [Window] Fix reloading windowcd from xserver request\n* [Build]  Add option to build with lto to meson.\n    Fix error in test.\n    (#1743)\n* [Build] Add option to disable imdkit at compile time. (#1742)\n* input method (#1735)\n    * input method draft\n    * restoring relese event\n    * using unused macro, removing debug code, handling disconnection\n    * review fixes, new update_im_window_pos method\n    * initializing variables correctly\n    * initializing im pos queue correctly\n    * ime window positioning\n    * add widget_get_y_pos() position\n    * [Build] Update makefile with imdkit\n    * [CI] Add imdkit as dependency.\n    * [XCB] rofi_view_paste don't throw warning, print debug.\n    * [XCB] rofi_view_paste lower 'failed to convert selection'\n    * [Build] Add minimum version check to imdkit\n    * new macro XCB_IMDKIT_1_0_3_LOWER\n    * [Build] Try to support old version of imdkit in meson/makefile.\n    * [Build] Fix typo in meson.build\n    * [XIM] Don't set use compound/set use utf8 when on old version.\n    * [Build] Allow building without imdkit.\n    * [Doc] Add imdkit to dependency list.\n* [Window] Make sure their is a trailing 0 on the workspace strings. (#1739)\n* [FileBrowser] Bind kb-delete-entry to toggle show-hidden.\n* [Textbox] Add a 'get_cursor_x_pos' function.\n* [man] re-gen manpage.\n* [DOC] Add parsing row options to dmenu manpage (#1734)\n* [Build] Fix icon install path for makefile. (#1733)\n* [Window] Small fixes to prefer-icon-theme option\n  Thanks to Kafva (https://github.com/Kafva) for the original patch.\n  (#1702)\n* [Window] Add -window-prefer-icon-theme option. (#1702)\n* [drun] Only pass path on launch, if one is set\n* The mode is filebrowser (not file-browser) (#1723)\n* [filebrowser] Add an option to show hidden files. (#1716)\n* [Doc] Update rofi-keys manpage with unset section\n* Add format option to disable padding with space the \"window-format\" entries (#1715)\n* [Script] Split mode string only once on :, allowing : in right part. (#1718)\n* [window] Check bitmask, not full comparison\n* Use `command -v` instead of `which` (#1704)\n* [Keyb] Add a -list-keybindings command.\n* Fix sed binary call with variable (#1707)\n* [listview] Add extra checks before resolving pointer. (#1703)\n* [Textbox] Add 'placeholder-markup' flag. (#1690)\n* [Test][Theme] Update test for downgrade error\n* [Theme] If no theme loaded, load default. Downgrade missing theme file to warning. (#1689)\n* [DMenu] reset variable correctly so keep-selection is initially off. (#1686)\n* Update test for # keybindings.\n* [View|Xcb] Add support to copy current selected item to clipboard (#378)\n* Include sys/stat.h for S_IWUSR (#1685)\n* [View] Tweak error message and instant/delayed switching.\n* [View] Change refilter timeout limit to be in time units (ms) (#1683)\n* [Combi] Fix possible memory leak.\n* [combi] Fix selecting entry with only bang as input.\n* [View] Increase default refilter-timeout-limit. (#1683)\n"
  },
  {
    "path": "releasenotes/1.7.7/release-1.7.7.markdown",
    "content": "# 1.7.7: Time Dilation\n\nA quick-fix release following reports after releasing the 1.7.6 release.\n\n## Issues\n\n### Drawing issue\n\nAfter the previous release some users experienced rofi being rendered to screen\nas a black box. The issue seems to be only hit on certain video cards/drivers\nsee the github issue [#2068](https://github.com/davatorium/rofi/issues/2068).It turned out on these systems using\n`cairo_push/pop_group` results in a black screen when the backing surface is\nusing the XCB library. When using other drivers, or rendering to a cairo image\nsurface.\nHopefully reverting to `cairo_store` and `cairo_restore` fixes this issue for everybody.\n\nIssue [#2068](https://github.com/davatorium/rofi/issues/2068)\n\n### Window mode missing some windows\n\nBecause of a wrong check some windows where misidentified as 'skip pager' and\nhidden from the view. This should now be resolved.\n\nIssue [#2071](https://github.com/davatorium/rofi/issues/2071)\n\n### 'Character' in config file broken\n\nA previous patch to make using strings more easy to use in the configuration\nfile broke settings that use the 'character' type as setting. Because not a lot\nof options use the 'Character' type , this has been 'resolved' by using the\n'String' type and picking the first ASCII character. \n\nIssue [#2070](https://github.com/davatorium/rofi/issues/2070)\n\n## improvements\n\nBeside these issues, also some improvements are included in this release. \n\n## Resolve 'rasinc' for @imports\n\nWhen importing a theme file like this:\n\n```css\n@import \"mytheme\"\n```\n\nRofi would find any file 'mytheme.rasi' in any of the theme paths.\nThis was missing the new extension for shared include files 'rasinc'.\nThis is now added when resolving.\n\nIssue [#2069](https://github.com/davatorium/rofi/issues/2069)\n\n## Desktop file DBus activation\n\nSome desktop files did not launch correctly because it did not implement the\nDBusActivation feature. While most desktop files did provide a fallback `Exec`\nentry, this seems to not always be the case. Rofi should now first try\nDBusActivation and fall back to the Exec if it does not succeed.\n\nIssue [#1924](https://github.com/davatorium/rofi/issues/1924)\n\n## Resolve `-config` identical to `-theme`\n\nif you pass an alternative config file, this is now resolved using the same\nlogic as the `-theme` argument. Making it easier to have multiple, alternative,\nconfiguration files.\n\nIssue [#2040](https://github.com/davatorium/rofi/issues/2040)\n\n## Changelog\n\n* [Widget] Don't use cairo_push/pop_group as it causes issues. (#2068)\n* Revert \"[window] Check bitmask, not full comparison\".  (#2071)\n* [Config] Remove character data type as it aliases with string. (#2070)\n* [Doc] Refer to releasenotes for updates in Changelog file. (#2069)\n* [Doc] Update theme documentation with import resolving update. (#2069)\n* [Themes] Update themes to import without rasi(nc) extensions. (#2069)\n* [Theme] Fix resolving of 'rasinc' extension when no extension is given. (#2069)\n* Be more diligent trying to resolve -config. (#2040)\n* Use FALSE instead of FALSE.\n* Resolve -config argument identical to a -theme argument. (#2040)\n* [DRun] If indicated by .desktop file, launch via dbus activation. (#1924)\n* [Website] Update website links and headers.\n"
  },
  {
    "path": "releasenotes/1.7.8/release-1.7.8.markdown",
    "content": "# 1.7.8\n\n## Fix drawing issue\n\nIn the last release we had some code that hit a bug in some graphics drivers.\nThe fix that went in had a side-effect causing borders not to be drawn as\nexpected. This release should fix that.\n\nIssue: #2076\n\n## DBusActivatable\n\nThe previously introduced DBusActivatable seems to cause some issues and\nconfusion. First if the application (dconf-editor looking at you) does not\nacknowledge it launched rofi stays open until it times out. By default this is\n15 seconds. We reduced the timeout to 1.5 seconds and added an option to\ndisable DBusActivatable.\n\nThe 2nd point is, that if you launch an application via DBusActivatable it is\nnot launched by rofi and does not inherits rofi's environment, but the one\nsystemd is configured to use for that user.\nThe archlinux documentation explains this and how to fix this [here](https://wiki.archlinux.org/title/Systemd/User#Environment_variables).\n\nIssue: #2077\n\n## CI Fixes\n\nBecause of some deprecation, the CI scripts are updated. It might be useful for\npeople who want to help to test the latest rofi that for every commit an\nartifact is build with a 'source package' you can install.\n\nYou can find them\n[here](https://github.com/davatorium/rofi/actions/workflows/build.yml) by\nclicking on the commit you want and scrolling to the bottom of the page. This\ncontains a zip with the two normal source tarballs.\n\n## Changelog\n\n* Fix buffer overflow in rofi -e after reading from stdin (#2082) (Thanks to\nFaule Socke)\n* [DRun] Reduce DBus timeout to 1500ms add option to disable DBusActivatable.\n  Issue: #2077\n* [CI] Do explicit compare with 'true'?\n* [CI] Fix typo in conditional.\n* [CI] Only make dist on one build.\n* [CI] Fix identical name?\n* [CI] Bump upload action to v4\n* [Widget] Actually remove ADD operator from border drawing.\n  Issue: #2076\n* [widget] Remove the ADD operator.\n  Issue: #2076\n* Add 1.7.7 docs to README.\n* Mark as dev version\n"
  },
  {
    "path": "releasenotes/1.7.9/release-1.7.9.markdown",
    "content": "# 1.7.9\n\n## Custom commands on events\n\nGiomatfois62 added a nice feature that allows you to execute a custom command\non different events. For example play a sound when accepting an entry.\n\nSee the\n[rofi-actions(5)](https://github.com/davatorium/rofi/blob/1.7.9/doc/rofi-actions.5.markdown)\nmanpage for more information.\n\n## NVidia workaround workaround\n\nBecause of oddness in nvidia drivers, we had an issue the whole screen turned\nblack if we used the 'over' operator in cairo. Working around this caused some\ndrawing issues with anti-aliasing. There now exists two flags to to work around\nthis workaround again. Either disable the workaround, or disable anti-aliasing.\n\nYou can set these options per widget:\n\n```css\nwidget {\n  border-disable-nvidia-workaround: true;\n  border-aa: false;\n}\n```\n\nIt's recommended to set it globally.\n\n```css\n* {\n  border-disable-nvidia-workaround: true;\n  border-aa: false;\n}\n```\n\n## IMDKit runtime disable option\n\nBecause IMDKit can break some keybindings, this can now be disabled at runtime.\nFor example if you try to bind only the 'Super' key, this can fix this.\n\nFor more information, see issue: #2124\n\n## Smartcase support\n\nThanks to Phanium, rofi now supports Vim style 'smartcase'. Can be enabled\nusing `-case-smart`.\n\nFore more information, see issue: #2060\n\n## Changelog\n\n* Add -imdkit config to toggle imdkit at runtime (#2124) (thx Amos Bird)\n* [Widget] Add 2 workaround for error in corner radius drawing\n* [rofi-sensible-terminal] Add ghostty (#2110)\n* [scrollbar] Add theming for rounded corners (#2108) (thx J0hannes101)\n* [DOC] Fix indenting of sub-bullets as mkdocs interpets them differently (#2112)\n* Fix typo in fullscreen-preview.rasi (#2113) (thx elig0n)\n* Add theming to hide text cursor if no text is put in (#2106) (thx J0hannes101)\n* [DRUN] Add option to exclude categories from drun #2102 (#2104) (thx J0hannes101)\n* [XCB] Don't keep casting from int to double to int\n* [Helper] Add a rofi_fallthrough macro to tell compiler fallthrough is intentional\n* [View] xcb_clear_area  fixed wrong argument order.\n* [DRun] Better handling of corrupted cache file.\n* Fix broken Pango link (#2096) (thx Emil)\n* [NKUtils] Drop support for binding Meta key. (#2095)\n* [View] Allow cycling through matching methods (#2091)\n* Fix wrong pointer `-replace` and small cleanup.\n* [Textbox] Small signedness fixes for password mask code.\n* [dmenu] Modified textbox password masking (#2067) (thx Zebra2711)\n* add smartcase support like vim (#2060) (thx Phanium)\n* [Mode] Fix wrong documentation header.\n* Execute custom user commands or scripts on a variety of rofi events (#2053) (thx giomatfois62)\n* Add option to enable the `kb-delete-entry` in script mode (#2087) (thx Tiou Lims)\n* [Window] Allow active window to be sorted on top. (#2048)\n* [Lexer] Allow for optional imports. (#2078)\n"
  },
  {
    "path": "releasenotes/2.0.0/release-2.0.0.markdown",
    "content": "# 2.0.0\n\nIn this release we merged back [lbonn](https://github.com/lbonn) his great wayland [port of rofi](https://github.com/lbonn/rofi) into mainline.\nWayland is now an officially supported backend.\n\n## Removal of autotools build system\n\nWith the merge of the wayland backend, for ease of maintenance, we dropped the autotools build system. We now only\nsupport the meson build system. Please see the updated\n[INSTALL](https://github.com/davatorium/rofi/blob/2.0.0/INSTALL.md)\ninstructions.\n\nYou can build rofi with only X11 or Wayland. It also supports or both backends enabled, where it automatically select the right backend.\n[See here](https://github.com/davatorium/rofi/blob/2.0.0/INSTALL.md#options-for-building) for more information about build options.\n\n## Dump info\n\nTo help bug reports, we added the command `rofi -info`.\nThis will print the selected backends. Compilation options, loaded plugins, scripts and more.\n\nAn example output:\n\n```\nDisplay backends:\n        • xcb\n        • wayland: selected\n\nMonitor layout:\n              ID: 58\n            name: DP-1\n           scale: 1\n        position: 0,0\n            size: 3840,2160\n            size: 600mm,340mm  dpi: 163,161\n\n\nDetected modes:\n        • window\n        • run\n        • +ssh\n        • +drun\n        • +combi\n        • keys\n        • filebrowser\n        • recursivebrowser\n\nDetected user scripts:\n\nCompile time options:\n        • Pango   version 1.56.4\n        • window  enabled\n        • drun    enabled\n        • asan    disabled\n        • imdkit  enabled\n        • xcb     enabled\n        • wayland enabled (1.23.1)\n\nFor more information see: man rofi\n                 Version: 2.0.0 (next)\n              Bugreports: https://github.com/davatorium/rofi/\n                 Support: https://github.com/davatorium/rofi/discussions\n                          #rofi @ libera.chat\n      Configuration file: /home/user/.config/rofi/config.rasi\n\nParsed files:\n        ‣ /home/user/.config/rofi/config.rasi\n```\n\n## Known issues\n\nSee the [README](https://github.com/davatorium/rofi/blob/2.0.0/README.md) for the full list.\n\n### Redraw on startup\n\nWith wayland, rofi only knows after the first surface is drawn, what the dpi and\nscale is. Because of this, it might need to redraw/resize elements (icons/text)\nafter displaying. This can generate a weird 'flicker' on startup. It will first\nload a lower resolution version of the icons (that the window manager scales\nup), then it gets updated with the real resolution and it then loads full\nresolution icons. Because icon loading is asynchronous, they will disappear and\nre-appear.\n\nThere are possible work-arounds, but those might cause weird artifacts with\nwindow managers that do animations, like hyprland. We are still looking into a\ngood solution. Help is welcome.\n\nIssue: [#2165](https://github.com/davatorium/rofi/issues/2165)\n\n### Close on click out of window\n\nIt is currently not possible, in a reliable way, to detect out of window clicks.\nSo under wayland this feature currently does not work.\n\nIssue: [#2158](https://github.com/davatorium/rofi/issues/2158)\n\n### No IMDKIT support in wayland\n\nThere is currently no imdkit support when using the wayland backend.\n\nIssue: [#131 orig repo](https://github.com/lbonn/rofi/issues/131)\n\n## Changelog\n\nThe changelog contains years of wayland patches and merges.\nThere is little use to list them all here in this releasenote.\nPlease check the full git log for changes.\n"
  },
  {
    "path": "resources/resources.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gresources>\n  <gresource prefix=\"/org/qtools/rofi\">\n    <file alias=\"default.rasi\">doc/default_theme.rasi</file>\n    <file alias=\"default_configuration.rasi\">doc/default_configuration.rasi</file>\n  </gresource>\n</gresources>\n"
  },
  {
    "path": "script/get_git_rev.sh",
    "content": "#!/usr/bin/env bash\n\nDIR=$1\nFILE=$2\nGIT=$(command -v git)\nSED=$(command -v sed)\n\nif [ -d \"${DIR}/.git/\" ] && [ -n \"${GIT}\" ]\nthen\n    echo -n \"#define GIT_VERSION \\\"\" > \"${FILE}.tmp\"\n    BRTG=\"$(${GIT} describe --tags --always --all | ${SED} -e 's:heads/::')\"\n    REV=\"$(${GIT} describe --tags --always --dirty| ${SED} -e 's:-g\\([a-f0-9]\\{7\\}\\):-git-\\1:g')\"\n    echo -n \"${REV} (${BRTG})\" >> \"${FILE}.tmp\"\n    echo \"\\\"\" >> \"${FILE}.tmp\"\nelse\n    echo \"#undef GIT_VERSION\" > \"${FILE}.tmp\"\nfi\n\nif [ ! -f \"${FILE}\" ] || ! diff \"${FILE}.tmp\" \"${FILE}\" >/dev/null\nthen\n    mv \"${FILE}.tmp\" \"${FILE}\"\nelse\n    rm \"${FILE}.tmp\"\nfi\n"
  },
  {
    "path": "script/rofi-sensible-terminal",
    "content": "#!/usr/bin/env bash\n#\n# This code is released in public domain by Han Boetes <han@mijncomputer.nl>\n# Updated by Dave Davenport <qball@gmpclient.org>\n#\n# This script tries to exec a terminal emulator by trying some known terminal\n# emulators.\n#\n# We welcome patches that add distribution-specific mechanisms to find the\n# preferred terminal emulator. On Debian, there is the x-terminal-emulator\n# symlink for example.\nfor terminal in $TERMINAL x-terminal-emulator urxvt rxvt st terminology qterminal Eterm aterm uxterm xterm roxterm xfce4-terminal.wrapper mate-terminal lxterminal konsole alacritty kitty wezterm foot ghostty; do\n\tif command -v $terminal >/dev/null 2>&1; then\n\t\texec $terminal \"$@\"\n\tfi\ndone\n\nrofi -e \"Failed to find a suitable terminal\"\n"
  },
  {
    "path": "script/rofi-theme-selector",
    "content": "#!/usr/bin/env bash\n#\n# This code is released in public domain by Dave Davenport <qball@gmpclient.org>\n#\n\n##\n# OS checking code as utilities could be different\n##\nOS=\"gnu\"\ncase \"$OSTYPE\" in\n    *linux*|*hurd*|*msys*|*cygwin*|*sua*|*interix*) OS=\"gnu\";;\n    *bsd*|*darwin*) OS=\"bsd\";;\n    *sunos*|*solaris*|*indiana*|*illumos*|*smartos*) OS=\"sun\";;\nesac\n\nROFI=$(command -v rofi)\nif [ $OS = \"bsd\" ]; then\n    SED=$(command -v gsed)\nelse\n    SED=$(command -v sed)\nfi\nMKTEMP=$(command -v mktemp)\n\nif [ -z \"${SED}\" ]\nthen\n    echo \"Did not find 'sed', script cannot continue.\"\n    exit 1\nfi\nif [ -z \"${MKTEMP}\" ]\nthen\n    echo \"Did not find 'mktemp', script cannot continue.\"\n    exit 1\nfi\nif [ -z \"${ROFI}\" ]\nthen\n    echo \"Did not find rofi, there is no point to continue.\"\n    exit 1\nfi\n\nTMP_CONFIG_FILE=$(${MKTEMP}).rasi\n\n##\n# Array with parts to the found themes.\n# And array with the printable name.\n##\ndeclare -a themes\ndeclare -a theme_names\n\n##\n# Function that tries to find all installed rofi themes.\n# This fills in #themes array and formats a displayable string #theme_names\n##\nfind_themes()\n{\n    DIRS=${XDG_DATA_DIRS}\n    OLDIFS=${IFS}\n    IFS=:\n    if [ -z \"${XDG_DATA_DIRS}\" ]\n    then\n        echo \"XDG_DATA_DIRS needs to be set for this script to function correctly.\"\n        echo -n \"Using dirs from \\$PATH: \"\n        DIRS=\n        # Iterate over items in $PATH\n        for p in ${PATH}; do\n            # Remove trailing / if exists.\n            x=${p%/}\n            # remove both /bin and /sbin and /games from end\n            x=${x%/bin}\n            x=${x%/sbin}\n            x=${x%/games}\n            # Add /share\n            x=${x}/share\n            # Check if entry exists Prepend : so :${x}: matches nicely\n            case \":${DIRS}\" in\n                *$x:*);;\n                *) DIRS+=\"$x:\";;\n            esac\n        done\n        # Remove trailing :\n        DIRS=${DIRS%:}\n        echo \"${DIRS}\"\n    fi\n    # Add user dir.\n    DIRS+=\":${XDG_DATA_HOME:-${HOME}/.local/share}\"\n    DIRS+=\":${XDG_CONFIG_HOME:-${HOME}/.config}\"\n    for p in ${DIRS}; do\n        p=${p%/}\n        TD=${p}/rofi/themes\n        if [ -n \"${p}\" ] && [ -d \"${TD}\" ]\n        then\n            echo \"Checking themes in: ${TD}\"\n            for file in ${TD}/*.rasi\n            do\n                if [ -f \"${file}\" ]\n                then\n                    themes+=(\"${file}\")\n                    FN=$(basename \"${file}\")\n                    NAME=${FN%.*}\n                    USER=$(${SED} -n 's/^.*User: \\(.*\\)/\\1/p' \"${file}\" | head -n 1 )\n                    if [ -z \"${USER}\" ]\n                    then\n                        theme_names+=(${NAME})\n                    else\n                        theme_names+=(\"${NAME} by ${USER}\")\n                    fi\n                fi\n           done\n        fi\n    done\n    IFS=${OLDIFS}\n}\n\n##\n# Create a copy of rofi\n##\ncreate_config_copy()\n{\n    ${ROFI} -dump-config > \"${TMP_CONFIG_FILE}\"\n    # remove theme entry.\n    ${SED} -i 's/^\\s*theme:\\s\\+\".*\"\\s*;//g' \"${TMP_CONFIG_FILE}\"\n}\n\n###\n# Print the list out so it can be displayed by rofi.\n##\ncreate_theme_list()\n{\n    OLDIFS=${IFS}\n    IFS='|'\n    for themen in ${theme_names[@]}\n    do\n        echo \"${themen}\"\n    done\n    IFS=${OLDIFS}\n}\n\n##\n# Thee indicate what entry is selected.\n##\ndeclare -i SELECTED\n\nselect_theme()\n{\n    local MORE_FLAGS=(-dmenu -format i -no-custom -p \"Theme\" -markup -config \"${TMP_CONFIG_FILE}\" -i)\n    MORE_FLAGS+=(-kb-custom-1 \"Alt-a\")\n    MORE_FLAGS+=(-u 2,3 -a 4,5 )\n    local CUR=\"default\"\n    while true\n    do\n        declare -i RTR\n        declare -i RES\n        local MESG=\"\"\"You can preview themes by hitting <b>Enter</b>.\n<b>Alt-a</b> to accept the new theme.\n<b>Escape</b> to cancel\nCurrent theme: <b>${CUR}</b>\n<span weight=\\\"bold\\\" size=\\\"xx-small\\\">When setting a new theme this will override previous theme settings.\nPlease update your config file if you have local modifications.</span>\"\"\"\n        THEME_FLAG=\n        if [ -n \"${SELECTED}\" ]\n        then\n            THEME_FLAG=\"-theme ${themes[${SELECTED}]}\"\n        fi\n        RES=$( create_theme_list | ${ROFI} ${THEME_FLAG} ${MORE_FLAGS[@]} -cycle -selected-row \"${SELECTED}\" -mesg \"${MESG}\")\n        RTR=$?\n        if [ \"${RTR}\" = 10 ]\n        then\n            return 0;\n        elif [ \"${RTR}\" = 1 ]\n        then\n            return 1;\n        elif [ \"${RTR}\" = 65 ]\n        then\n            return 1;\n        fi\n        CUR=${theme_names[${RES}]}\n        SELECTED=${RES}\n    done\n}\n\n###\n# Create if not exists, then removes #include of .theme file (if present) and add the selected theme to the end.\n# Repeated calls should leave the config clean-ish\n###\nset_theme()\n{\n    CDIR=\"${XDG_CONFIG_HOME:-${HOME}/.config}/rofi\"\n    if [ ! -d \"${CDIR}\" ]\n    then\n        mkdir -p \"${CDIR}\"\n    fi\n    # on BSD & MacOS readlink acts differently\n    if [ $OS = \"bsd\" ]; then\n        get_link=\"$(realpath \"${CDIR}\")/config.rasi\"\n    else\n        get_link=$(readlink -f \"${CDIR}/config.rasi\")\n    fi\n    if [[ ! -f \"${get_link}\" ]]\n    then\n       touch \"${get_link}\"\n    fi\n\n    # Comment old base theme, not replace as it may be modified after the line\n    ${SED} -i '/^\\s*@theme/ s,^,//,' \"${get_link}\"\n    echo -e \"\\n@theme \\\"${1}\\\"\" >> \"${get_link}\"\n}\n\n############################################################################################################\n# Actual program execution\n###########################################################################################################\n##\n# Find all themes\n##\nfind_themes\n\n##\n# Do check if there are themes.\n##\nif [ ${#themes[@]} = 0 ]\nthen\n    ${ROFI} -e \"No themes found.\"\n    exit 0\nfi\n\n##\n# Create copy of config to play with in preview\n##\ncreate_config_copy\n\n##\n# Show the themes to user.\n##\nif select_theme && [ -n \"${SELECTED}\" ]\nthen\n    # Set theme\n    set_theme \"${themes[${SELECTED}]}\"\nfi\n\n##\n# Remove temp. config.\n##\nrm -- \"${TMP_CONFIG_FILE}\"\n"
  },
  {
    "path": "source/css-colors.c",
    "content": "#include \"css-colors.h\"\nconst CSSColor CSSColors[] = {\n    {.name = \"AliceBlue\", .r = 0xF0, .g = 0xF8, .b = 0xFF},\n    {.name = \"AntiqueWhite\", .r = 0xFA, .g = 0xEB, .b = 0xD7},\n    {.name = \"Aqua\", .r = 0x00, .g = 0xFF, .b = 0xFF},\n    {.name = \"Aquamarine\", .r = 0x7F, .g = 0xFF, .b = 0xD4},\n    {.name = \"Azure\", .r = 0xF0, .g = 0xFF, .b = 0xFF},\n    {.name = \"Beige\", .r = 0xF5, .g = 0xF5, .b = 0xDC},\n    {.name = \"Bisque\", .r = 0xFF, .g = 0xE4, .b = 0xC4},\n    {.name = \"Black\", .r = 0x00, .g = 0x00, .b = 0x00},\n    {.name = \"BlanchedAlmond\", .r = 0xFF, .g = 0xEB, .b = 0xCD},\n    {.name = \"Blue\", .r = 0x00, .g = 0x00, .b = 0xFF},\n    {.name = \"BlueViolet\", .r = 0x8A, .g = 0x2B, .b = 0xE2},\n    {.name = \"Brown\", .r = 0xA5, .g = 0x2A, .b = 0x2A},\n    {.name = \"BurlyWood\", .r = 0xDE, .g = 0xB8, .b = 0x87},\n    {.name = \"CadetBlue\", .r = 0x5F, .g = 0x9E, .b = 0xA0},\n    {.name = \"Chartreuse\", .r = 0x7F, .g = 0xFF, .b = 0x00},\n    {.name = \"Chocolate\", .r = 0xD2, .g = 0x69, .b = 0x1E},\n    {.name = \"Coral\", .r = 0xFF, .g = 0x7F, .b = 0x50},\n    {.name = \"CornflowerBlue\", .r = 0x64, .g = 0x95, .b = 0xED},\n    {.name = \"Cornsilk\", .r = 0xFF, .g = 0xF8, .b = 0xDC},\n    {.name = \"Crimson\", .r = 0xDC, .g = 0x14, .b = 0x3C},\n    {.name = \"Cyan\", .r = 0x00, .g = 0xFF, .b = 0xFF},\n    {.name = \"DarkBlue\", .r = 0x00, .g = 0x00, .b = 0x8B},\n    {.name = \"DarkCyan\", .r = 0x00, .g = 0x8B, .b = 0x8B},\n    {.name = \"DarkGoldenRod\", .r = 0xB8, .g = 0x86, .b = 0x0B},\n    {.name = \"DarkGray\", .r = 0xA9, .g = 0xA9, .b = 0xA9},\n    {.name = \"DarkGrey\", .r = 0xA9, .g = 0xA9, .b = 0xA9},\n    {.name = \"DarkGreen\", .r = 0x00, .g = 0x64, .b = 0x00},\n    {.name = \"DarkKhaki\", .r = 0xBD, .g = 0xB7, .b = 0x6B},\n    {.name = \"DarkMagenta\", .r = 0x8B, .g = 0x00, .b = 0x8B},\n    {.name = \"DarkOliveGreen\", .r = 0x55, .g = 0x6B, .b = 0x2F},\n    {.name = \"DarkOrange\", .r = 0xFF, .g = 0x8C, .b = 0x00},\n    {.name = \"DarkOrchid\", .r = 0x99, .g = 0x32, .b = 0xCC},\n    {.name = \"DarkRed\", .r = 0x8B, .g = 0x00, .b = 0x00},\n    {.name = \"DarkSalmon\", .r = 0xE9, .g = 0x96, .b = 0x7A},\n    {.name = \"DarkSeaGreen\", .r = 0x8F, .g = 0xBC, .b = 0x8F},\n    {.name = \"DarkSlateBlue\", .r = 0x48, .g = 0x3D, .b = 0x8B},\n    {.name = \"DarkSlateGray\", .r = 0x2F, .g = 0x4F, .b = 0x4F},\n    {.name = \"DarkSlateGrey\", .r = 0x2F, .g = 0x4F, .b = 0x4F},\n    {.name = \"DarkTurquoise\", .r = 0x00, .g = 0xCE, .b = 0xD1},\n    {.name = \"DarkViolet\", .r = 0x94, .g = 0x00, .b = 0xD3},\n    {.name = \"DeepPink\", .r = 0xFF, .g = 0x14, .b = 0x93},\n    {.name = \"DeepSkyBlue\", .r = 0x00, .g = 0xBF, .b = 0xFF},\n    {.name = \"DimGray\", .r = 0x69, .g = 0x69, .b = 0x69},\n    {.name = \"DimGrey\", .r = 0x69, .g = 0x69, .b = 0x69},\n    {.name = \"DodgerBlue\", .r = 0x1E, .g = 0x90, .b = 0xFF},\n    {.name = \"FireBrick\", .r = 0xB2, .g = 0x22, .b = 0x22},\n    {.name = \"FloralWhite\", .r = 0xFF, .g = 0xFA, .b = 0xF0},\n    {.name = \"ForestGreen\", .r = 0x22, .g = 0x8B, .b = 0x22},\n    {.name = \"Fuchsia\", .r = 0xFF, .g = 0x00, .b = 0xFF},\n    {.name = \"Gainsboro\", .r = 0xDC, .g = 0xDC, .b = 0xDC},\n    {.name = \"GhostWhite\", .r = 0xF8, .g = 0xF8, .b = 0xFF},\n    {.name = \"Gold\", .r = 0xFF, .g = 0xD7, .b = 0x00},\n    {.name = \"GoldenRod\", .r = 0xDA, .g = 0xA5, .b = 0x20},\n    {.name = \"Gray\", .r = 0x80, .g = 0x80, .b = 0x80},\n    {.name = \"Grey\", .r = 0x80, .g = 0x80, .b = 0x80},\n    {.name = \"Green\", .r = 0x00, .g = 0x80, .b = 0x00},\n    {.name = \"GreenYellow\", .r = 0xAD, .g = 0xFF, .b = 0x2F},\n    {.name = \"HoneyDew\", .r = 0xF0, .g = 0xFF, .b = 0xF0},\n    {.name = \"HotPink\", .r = 0xFF, .g = 0x69, .b = 0xB4},\n    {.name = \"IndianRed\", .r = 0xCD, .g = 0x5C, .b = 0x5C},\n    {.name = \"Indigo\", .r = 0x4B, .g = 0x00, .b = 0x82},\n    {.name = \"Ivory\", .r = 0xFF, .g = 0xFF, .b = 0xF0},\n    {.name = \"Khaki\", .r = 0xF0, .g = 0xE6, .b = 0x8C},\n    {.name = \"Lavender\", .r = 0xE6, .g = 0xE6, .b = 0xFA},\n    {.name = \"LavenderBlush\", .r = 0xFF, .g = 0xF0, .b = 0xF5},\n    {.name = \"LawnGreen\", .r = 0x7C, .g = 0xFC, .b = 0x00},\n    {.name = \"LemonChiffon\", .r = 0xFF, .g = 0xFA, .b = 0xCD},\n    {.name = \"LightBlue\", .r = 0xAD, .g = 0xD8, .b = 0xE6},\n    {.name = \"LightCoral\", .r = 0xF0, .g = 0x80, .b = 0x80},\n    {.name = \"LightCyan\", .r = 0xE0, .g = 0xFF, .b = 0xFF},\n    {.name = \"LightGoldenRodYellow\", .r = 0xFA, .g = 0xFA, .b = 0xD2},\n    {.name = \"LightGray\", .r = 0xD3, .g = 0xD3, .b = 0xD3},\n    {.name = \"LightGrey\", .r = 0xD3, .g = 0xD3, .b = 0xD3},\n    {.name = \"LightGreen\", .r = 0x90, .g = 0xEE, .b = 0x90},\n    {.name = \"LightPink\", .r = 0xFF, .g = 0xB6, .b = 0xC1},\n    {.name = \"LightSalmon\", .r = 0xFF, .g = 0xA0, .b = 0x7A},\n    {.name = \"LightSeaGreen\", .r = 0x20, .g = 0xB2, .b = 0xAA},\n    {.name = \"LightSkyBlue\", .r = 0x87, .g = 0xCE, .b = 0xFA},\n    {.name = \"LightSlateGray\", .r = 0x77, .g = 0x88, .b = 0x99},\n    {.name = \"LightSlateGrey\", .r = 0x77, .g = 0x88, .b = 0x99},\n    {.name = \"LightSteelBlue\", .r = 0xB0, .g = 0xC4, .b = 0xDE},\n    {.name = \"LightYellow\", .r = 0xFF, .g = 0xFF, .b = 0xE0},\n    {.name = \"Lime\", .r = 0x00, .g = 0xFF, .b = 0x00},\n    {.name = \"LimeGreen\", .r = 0x32, .g = 0xCD, .b = 0x32},\n    {.name = \"Linen\", .r = 0xFA, .g = 0xF0, .b = 0xE6},\n    {.name = \"Magenta\", .r = 0xFF, .g = 0x00, .b = 0xFF},\n    {.name = \"Maroon\", .r = 0x80, .g = 0x00, .b = 0x00},\n    {.name = \"MediumAquaMarine\", .r = 0x66, .g = 0xCD, .b = 0xAA},\n    {.name = \"MediumBlue\", .r = 0x00, .g = 0x00, .b = 0xCD},\n    {.name = \"MediumOrchid\", .r = 0xBA, .g = 0x55, .b = 0xD3},\n    {.name = \"MediumPurple\", .r = 0x93, .g = 0x70, .b = 0xDB},\n    {.name = \"MediumSeaGreen\", .r = 0x3C, .g = 0xB3, .b = 0x71},\n    {.name = \"MediumSlateBlue\", .r = 0x7B, .g = 0x68, .b = 0xEE},\n    {.name = \"MediumSpringGreen\", .r = 0x00, .g = 0xFA, .b = 0x9A},\n    {.name = \"MediumTurquoise\", .r = 0x48, .g = 0xD1, .b = 0xCC},\n    {.name = \"MediumVioletRed\", .r = 0xC7, .g = 0x15, .b = 0x85},\n    {.name = \"MidnightBlue\", .r = 0x19, .g = 0x19, .b = 0x70},\n    {.name = \"MintCream\", .r = 0xF5, .g = 0xFF, .b = 0xFA},\n    {.name = \"MistyRose\", .r = 0xFF, .g = 0xE4, .b = 0xE1},\n    {.name = \"Moccasin\", .r = 0xFF, .g = 0xE4, .b = 0xB5},\n    {.name = \"NavajoWhite\", .r = 0xFF, .g = 0xDE, .b = 0xAD},\n    {.name = \"Navy\", .r = 0x00, .g = 0x00, .b = 0x80},\n    {.name = \"OldLace\", .r = 0xFD, .g = 0xF5, .b = 0xE6},\n    {.name = \"Olive\", .r = 0x80, .g = 0x80, .b = 0x00},\n    {.name = \"OliveDrab\", .r = 0x6B, .g = 0x8E, .b = 0x23},\n    {.name = \"Orange\", .r = 0xFF, .g = 0xA5, .b = 0x00},\n    {.name = \"OrangeRed\", .r = 0xFF, .g = 0x45, .b = 0x00},\n    {.name = \"Orchid\", .r = 0xDA, .g = 0x70, .b = 0xD6},\n    {.name = \"PaleGoldenRod\", .r = 0xEE, .g = 0xE8, .b = 0xAA},\n    {.name = \"PaleGreen\", .r = 0x98, .g = 0xFB, .b = 0x98},\n    {.name = \"PaleTurquoise\", .r = 0xAF, .g = 0xEE, .b = 0xEE},\n    {.name = \"PaleVioletRed\", .r = 0xDB, .g = 0x70, .b = 0x93},\n    {.name = \"PapayaWhip\", .r = 0xFF, .g = 0xEF, .b = 0xD5},\n    {.name = \"PeachPuff\", .r = 0xFF, .g = 0xDA, .b = 0xB9},\n    {.name = \"Peru\", .r = 0xCD, .g = 0x85, .b = 0x3F},\n    {.name = \"Pink\", .r = 0xFF, .g = 0xC0, .b = 0xCB},\n    {.name = \"Plum\", .r = 0xDD, .g = 0xA0, .b = 0xDD},\n    {.name = \"PowderBlue\", .r = 0xB0, .g = 0xE0, .b = 0xE6},\n    {.name = \"Purple\", .r = 0x80, .g = 0x00, .b = 0x80},\n    {.name = \"RebeccaPurple\", .r = 0x66, .g = 0x33, .b = 0x99},\n    {.name = \"Red\", .r = 0xFF, .g = 0x00, .b = 0x00},\n    {.name = \"RosyBrown\", .r = 0xBC, .g = 0x8F, .b = 0x8F},\n    {.name = \"RoyalBlue\", .r = 0x41, .g = 0x69, .b = 0xE1},\n    {.name = \"SaddleBrown\", .r = 0x8B, .g = 0x45, .b = 0x13},\n    {.name = \"Salmon\", .r = 0xFA, .g = 0x80, .b = 0x72},\n    {.name = \"SandyBrown\", .r = 0xF4, .g = 0xA4, .b = 0x60},\n    {.name = \"SeaGreen\", .r = 0x2E, .g = 0x8B, .b = 0x57},\n    {.name = \"SeaShell\", .r = 0xFF, .g = 0xF5, .b = 0xEE},\n    {.name = \"Sienna\", .r = 0xA0, .g = 0x52, .b = 0x2D},\n    {.name = \"Silver\", .r = 0xC0, .g = 0xC0, .b = 0xC0},\n    {.name = \"SkyBlue\", .r = 0x87, .g = 0xCE, .b = 0xEB},\n    {.name = \"SlateBlue\", .r = 0x6A, .g = 0x5A, .b = 0xCD},\n    {.name = \"SlateGray\", .r = 0x70, .g = 0x80, .b = 0x90},\n    {.name = \"SlateGrey\", .r = 0x70, .g = 0x80, .b = 0x90},\n    {.name = \"Snow\", .r = 0xFF, .g = 0xFA, .b = 0xFA},\n    {.name = \"SpringGreen\", .r = 0x00, .g = 0xFF, .b = 0x7F},\n    {.name = \"SteelBlue\", .r = 0x46, .g = 0x82, .b = 0xB4},\n    {.name = \"Tan\", .r = 0xD2, .g = 0xB4, .b = 0x8C},\n    {.name = \"Teal\", .r = 0x00, .g = 0x80, .b = 0x80},\n    {.name = \"Thistle\", .r = 0xD8, .g = 0xBF, .b = 0xD8},\n    {.name = \"Tomato\", .r = 0xFF, .g = 0x63, .b = 0x47},\n    {.name = \"Turquoise\", .r = 0x40, .g = 0xE0, .b = 0xD0},\n    {.name = \"Violet\", .r = 0xEE, .g = 0x82, .b = 0xEE},\n    {.name = \"Wheat\", .r = 0xF5, .g = 0xDE, .b = 0xB3},\n    {.name = \"White\", .r = 0xFF, .g = 0xFF, .b = 0xFF},\n    {.name = \"WhiteSmoke\", .r = 0xF5, .g = 0xF5, .b = 0xF5},\n    {.name = \"Yellow\", .r = 0xFF, .g = 0xFF, .b = 0x00},\n    {.name = \"YellowGreen\", .r = 0x9A, .g = 0xCD, .b = 0x32}};\n\nconst unsigned int num_CSSColors = sizeof(CSSColors) / sizeof(*CSSColors);\n"
  },
  {
    "path": "source/display.c",
    "content": "#include \"keyb.h\"\n#include <glib.h>\n\n#include \"display.h\"\n#include \"display-internal.h\"\n\n#include \"view.h\"\n\n#include \"view-internal.h\"\n\nstatic const display_proxy *proxy;\n\nvoid display_init(const display_proxy *disp_in) {\n  proxy = disp_in;\n  view_init(proxy->view());\n}\n\nint monitor_active(workarea *mon) { return proxy->monitor_active(mon); }\n\nvoid display_set_input_focus(guint w) { proxy->set_input_focus(w); }\n\nvoid display_revert_input_focus(void) { proxy->revert_input_focus(); }\n\ngboolean display_setup(GMainLoop *main_loop, NkBindings *bindings) {\n  return proxy->setup(main_loop, bindings);\n}\n\ngboolean display_late_setup(void) { return proxy->late_setup(); }\n\nvoid display_early_cleanup(void) { proxy->early_cleanup(); }\n\nvoid display_cleanup(void) { proxy->cleanup(); }\n\nvoid display_dump_monitor_layout(void) { proxy->dump_monitor_layout(); }\n\nvoid display_startup_notification(RofiHelperExecuteContext *context,\n                                  GSpawnChildSetupFunc *child_setup,\n                                  gpointer *user_data) {\n  proxy->startup_notification(context, child_setup, user_data);\n}\n\nguint display_scale(void) { return proxy->scale(); }\n\nvoid display_get_clipboard_data(enum clipboard_type type, ClipboardCb callback, void* user_data) {\n  proxy->get_clipboard_data(type, callback, user_data);\n}\n\nvoid display_set_fullscreen_mode(void) { proxy->set_fullscreen_mode(); }\n"
  },
  {
    "path": "source/helper.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain for this helper. */\n#include \"config.h\"\n#define G_LOG_DOMAIN \"Helper\"\n\n#include \"display.h\"\n#include \"helper-theme.h\"\n#include \"helper.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"view.h\"\n#include <ctype.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <glib.h>\n#include <glib/gstdio.h>\n#include <limits.h>\n#include <pango/pango-fontmap.h>\n#include <pango/pango.h>\n#include <pango/pangocairo.h>\n#include <pwd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/file.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\nconst char *const MatchingMethodStr[MM_NUM_MATCHERS] = {\n    \"Normal\", \"Regex\", \"Glob\", \"Fuzzy\", \"Prefix\"};\n\nstatic int MatchingMethodEnabled[MM_NUM_MATCHERS] = {\n    MM_NORMAL,\n    -1,\n};\nstatic int NUMMatchingMethodEnabled = 1;\nstatic int CurrentMatchingMethod = 0;\n\n/**\n * Textual description of positioning rofi.\n */\nconst char *const monitor_position_entries[] = {\n    \"on focused monitor\", \"on focused window\", \"at mouse pointer\",\n    \"on monitor with focused window\", \"on monitor that has mouse pointer\"};\n/** copy of the argc for use in commandline argument parser. */\nint stored_argc = 0;\n/** copy of the argv pointer for use in the commandline argument parser */\nchar **stored_argv = NULL;\n\nchar *helper_string_replace_if_exists_v(char *string, GHashTable *h);\n\nconst char *helper_get_matching_mode_str(void) {\n  return MatchingMethodStr[config.matching_method];\n}\nvoid helper_select_next_matching_mode(void) {\n\n  CurrentMatchingMethod++;\n  CurrentMatchingMethod %= NUMMatchingMethodEnabled;\n  config.matching_method = MatchingMethodEnabled[CurrentMatchingMethod];\n}\nvoid helper_select_previous_matching_mode(void) {\n  CurrentMatchingMethod--;\n  if (CurrentMatchingMethod < 0) {\n    CurrentMatchingMethod = NUMMatchingMethodEnabled - 1;\n  }\n  config.matching_method = MatchingMethodEnabled[CurrentMatchingMethod];\n}\n\nvoid cmd_set_arguments(int argc, char **argv) {\n  stored_argc = argc;\n  stored_argv = argv;\n}\n\nint helper_parse_setup(char *string, char ***output, int *length, ...) {\n  GError *error = NULL;\n  GHashTable *h;\n  h = g_hash_table_new(g_str_hash, g_str_equal);\n  // By default, we insert terminal and ssh-client\n  g_hash_table_insert(h, \"{terminal}\", config.terminal_emulator);\n  g_hash_table_insert(h, \"{ssh-client}\", config.ssh_client);\n  // Add list from variable arguments.\n  va_list ap;\n  va_start(ap, length);\n  while (1) {\n    char *key = va_arg(ap, char *);\n    if (key == (char *)0) {\n      break;\n    }\n    char *value = va_arg(ap, char *);\n    if (value == (char *)0) {\n      break;\n    }\n    g_hash_table_insert(h, key, value);\n  }\n  va_end(ap);\n\n  char *res = helper_string_replace_if_exists_v(string, h);\n  // Destroy key-value storage.\n  g_hash_table_destroy(h);\n  // Parse the string into shell arguments.\n  if (g_shell_parse_argv(res, length, output, &error)) {\n    g_free(res);\n    return TRUE;\n  }\n  g_free(res);\n  // Throw error if shell parsing fails.\n  if (error) {\n    char *msg = g_strdup_printf(\"Failed to parse: '%s'\\nError: '%s'\", string,\n                                error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n  }\n  return FALSE;\n}\n\nvoid helper_tokenize_free(rofi_int_matcher **tokens) {\n  for (size_t i = 0; tokens && tokens[i]; i++) {\n    g_regex_unref((GRegex *)tokens[i]->regex);\n    g_free(tokens[i]);\n  }\n  g_free(tokens);\n}\n\nstatic gchar *glob_to_regex(const char *input) {\n  gchar *r = g_regex_escape_string(input, -1);\n  size_t str_l = strlen(r);\n  for (size_t i = 0; i < str_l; i++) {\n    if (r[i] == '\\\\') {\n      if (r[i + 1] == '*') {\n        r[i] = '.';\n      } else if (r[i + 1] == '?') {\n        r[i + 1] = 'S';\n      }\n      i++;\n    }\n  }\n  return r;\n}\nstatic gchar *fuzzy_to_regex(const char *input) {\n  char *retv = NULL;\n  GString *str = g_string_new(\"\");\n  gchar *r = g_regex_escape_string(input, -1);\n  gchar *iter;\n  int first = 1;\n  for (iter = r; iter && *iter != '\\0'; iter = g_utf8_next_char(iter)) {\n    if (first) {\n      g_string_append(str, \"(\");\n    } else {\n      g_string_append(str, \".*?(\");\n    }\n    if (*iter == '\\\\') {\n      g_string_append_c(str, '\\\\');\n      iter = g_utf8_next_char(iter);\n      // If EOL, break out of for loop.\n      if ((*iter) == '\\0') {\n        break;\n      }\n    }\n    g_string_append_unichar(str, g_utf8_get_char(iter));\n    g_string_append(str, \")\");\n    first = 0;\n  }\n  g_free(r);\n  retv = g_string_free(str, FALSE);\n  return retv;\n}\n\nstatic gchar *prefix_regex(const char *input) {\n  gchar *r = g_regex_escape_string(input, -1);\n  char *retv = g_strconcat(\"\\\\b\", r, NULL);\n  g_free(r);\n  return retv;\n}\n\nstatic char *utf8_helper_simplify_string(const char *os) {\n  char buf[6] = {\n      0,\n  };\n\n  // Normalize the string to a fully decomposed form, then filter out\n  // mark/accent characters.\n  char *s = g_utf8_normalize(os, -1, G_NORMALIZE_ALL);\n  ssize_t str_size = (g_utf8_strlen(s, -1) * 6 + 2 + 1) * sizeof(char);\n  char *str = g_malloc0(str_size);\n  char *striter = str;\n  for (const char *iter = s; iter && *iter; iter = g_utf8_next_char(iter)) {\n    gunichar uc = g_utf8_get_char(iter);\n    if (!g_unichar_ismark(uc)) {\n      int l = g_unichar_to_utf8(uc, buf);\n      memcpy(striter, buf, l);\n      striter += l;\n    }\n  }\n  g_free(s);\n\n  return str;\n}\n\n// Macro for quickly generating regex for matching.\nstatic inline GRegex *R(const char *s, int case_sensitive) {\n  if (config.normalize_match) {\n    char *str = utf8_helper_simplify_string(s);\n\n    GRegex *r = g_regex_new(\n        str, G_REGEX_OPTIMIZE | ((case_sensitive) ? 0 : G_REGEX_CASELESS), 0,\n        NULL);\n\n    g_free(str);\n    return r;\n  }\n  return g_regex_new(\n      s, G_REGEX_OPTIMIZE | ((case_sensitive) ? 0 : G_REGEX_CASELESS), 0, NULL);\n}\n\nstatic rofi_int_matcher *create_regex(const char *input, int case_sensitive) {\n  GRegex *retv = NULL;\n  gchar *r;\n  rofi_int_matcher *rv = g_malloc0(sizeof(rofi_int_matcher));\n  if (input && input[0] == config.matching_negate_char) {\n    rv->invert = 1;\n    input++;\n  }\n  switch (config.matching_method) {\n  case MM_GLOB:\n    r = glob_to_regex(input);\n    retv = R(r, case_sensitive);\n    g_free(r);\n    break;\n  case MM_REGEX:\n    retv = R(input, case_sensitive);\n    if (retv == NULL) {\n      r = g_regex_escape_string(input, -1);\n      retv = R(r, case_sensitive);\n      g_free(r);\n    }\n    break;\n  case MM_FUZZY:\n    r = fuzzy_to_regex(input);\n    retv = R(r, case_sensitive);\n    g_free(r);\n    break;\n  case MM_PREFIX:\n    r = prefix_regex(input);\n    retv = R(r, case_sensitive);\n    g_free(r);\n    break;\n  default:\n    r = g_regex_escape_string(input, -1);\n    retv = R(r, case_sensitive);\n    g_free(r);\n    break;\n  }\n  rv->regex = retv;\n  return rv;\n}\nrofi_int_matcher **helper_tokenize(const char *input, int case_sensitive) {\n  if (input == NULL) {\n    return NULL;\n  }\n  size_t len = strlen(input);\n  if (len == 0) {\n    return NULL;\n  }\n\n  char *saveptr = NULL, *token;\n  rofi_int_matcher **retv = NULL;\n  if (!config.tokenize) {\n    retv = g_malloc0(sizeof(rofi_int_matcher *) * 2);\n    retv[0] = create_regex(input, case_sensitive);\n    return retv;\n  }\n\n  // First entry is always full (modified) stringtext.\n  int num_tokens = 0;\n\n  // Copy the string, 'strtok_r' modifies it.\n  char *str = g_strdup(input);\n\n  // Iterate over tokens.\n  // strtok should still be valid for utf8.\n  const char *const sep = \" \";\n  for (token = strtok_r(str, sep, &saveptr); token != NULL;\n       token = strtok_r(NULL, sep, &saveptr)) {\n    retv = g_realloc(retv, sizeof(rofi_int_matcher *) * (num_tokens + 2));\n    retv[num_tokens] = create_regex(token, case_sensitive);\n    retv[num_tokens + 1] = NULL;\n    num_tokens++;\n  }\n  // Free str.\n  g_free(str);\n  return retv;\n}\n\n// cli arg handling\nint find_arg(const char *const key) {\n  int i;\n\n  for (i = 0; i < stored_argc && strcasecmp(stored_argv[i], key); i++) {\n    ;\n  }\n\n  return i < stored_argc ? i : -1;\n}\nint find_arg_str(const char *const key, char **val) {\n  int i = find_arg(key);\n\n  if (val != NULL && i > 0 && i < stored_argc - 1) {\n    *val = stored_argv[i + 1];\n    return TRUE;\n  }\n  return FALSE;\n}\n\nconst char **find_arg_strv(const char *const key) {\n  const char **retv = NULL;\n  int length = 0;\n  for (int i = 0; i < stored_argc; i++) {\n    if (i < (stored_argc - 1) && strcasecmp(stored_argv[i], key) == 0) {\n      length++;\n    }\n  }\n  if (length > 0) {\n    retv = g_malloc0((length + 1) * sizeof(char *));\n    int index = 0;\n    for (int i = 0; i < stored_argc; i++) {\n      if (i < (stored_argc - 1) && strcasecmp(stored_argv[i], key) == 0) {\n        retv[index++] = stored_argv[i + 1];\n      }\n    }\n  }\n  return retv;\n}\n\nint find_arg_int(const char *const key, int *val) {\n  int i = find_arg(key);\n\n  if (val != NULL && i > 0 && i < (stored_argc - 1)) {\n    *val = strtol(stored_argv[i + 1], NULL, 10);\n    return TRUE;\n  }\n  return FALSE;\n}\nint find_arg_uint(const char *const key, unsigned int *val) {\n  int i = find_arg(key);\n\n  if (val != NULL && i > 0 && i < (stored_argc - 1)) {\n    *val = strtoul(stored_argv[i + 1], NULL, 10);\n    return TRUE;\n  }\n  return FALSE;\n}\n\nchar helper_parse_char(const char *arg) {\n  const size_t len = strlen(arg);\n  // If the length is 1, it is not escaped.\n  if (len == 1) {\n    return arg[0];\n  }\n  // If the length is 2 and the first character is '\\', we unescape it.\n  if (len == 2 && arg[0] == '\\\\') {\n    switch (arg[1]) {\n    // New line\n    case 'n':\n      return '\\n';\n    // Bell\n    case 'a':\n      return '\\a';\n    // Backspace\n    case 'b':\n      return '\\b';\n    // Tab\n    case 't':\n      return '\\t';\n    // Vertical tab\n    case 'v':\n      return '\\v';\n    // Form feed\n    case 'f':\n      return '\\f';\n    // Carriage return\n    case 'r':\n      return '\\r';\n    // Forward slash\n    case '\\\\':\n      return '\\\\';\n    // 0 line.\n    case '0':\n      return '\\0';\n    default:\n      break;\n    }\n  }\n  if (len > 2 && arg[0] == '\\\\' && arg[1] == 'x') {\n    return (char)strtol(&arg[2], NULL, 16);\n  }\n  g_warning(\"Failed to parse character string: \\\"%s\\\"\", arg);\n  // for now default to newline.\n  return '\\n';\n}\n\nint find_arg_char(const char *const key, char *val) {\n  int i = find_arg(key);\n\n  if (val != NULL && i > 0 && i < (stored_argc - 1)) {\n    *val = helper_parse_char(stored_argv[i + 1]);\n    return TRUE;\n  }\n  return FALSE;\n}\n\nvoid helper_token_match_set_pango_attr_on_style(PangoAttrList *retv, int start,\n                                                int end,\n                                                RofiHighlightColorStyle th) {\n  if (th.style & ROFI_HL_BOLD) {\n    PangoAttribute *pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n#if PANGO_VERSION_CHECK(1, 50, 0)\n  if (th.style & ROFI_HL_UPPERCASE) {\n    PangoAttribute *pa =\n        pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_UPPERCASE);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n  if (th.style & ROFI_HL_LOWERCASE) {\n    PangoAttribute *pa =\n        pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_LOWERCASE);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n  if (th.style & ROFI_HL_CAPITALIZE) {\n#if 0\n    PangoAttribute *pa =\n          pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_CAPITALIZE);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n#endif\n    // Disabled because of bug in pango\n  }\n#endif\n  if (th.style & ROFI_HL_UNDERLINE) {\n    PangoAttribute *pa = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n  if (th.style & ROFI_HL_STRIKETHROUGH) {\n    PangoAttribute *pa = pango_attr_strikethrough_new(TRUE);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n  if (th.style & ROFI_HL_ITALIC) {\n    PangoAttribute *pa = pango_attr_style_new(PANGO_STYLE_ITALIC);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n  }\n  if (th.style & ROFI_HL_COLOR) {\n    PangoAttribute *pa = pango_attr_foreground_new(\n        th.color.red * 65535, th.color.green * 65535, th.color.blue * 65535);\n    pa->start_index = start;\n    pa->end_index = end;\n    pango_attr_list_insert(retv, pa);\n\n    if (th.color.alpha < 1.0) {\n      pa = pango_attr_foreground_alpha_new(th.color.alpha * 65535);\n      pa->start_index = start;\n      pa->end_index = end;\n      pango_attr_list_insert(retv, pa);\n    }\n  }\n}\n\nPangoAttrList *helper_token_match_get_pango_attr(RofiHighlightColorStyle th,\n                                                 rofi_int_matcher **tokens,\n                                                 const char *input,\n                                                 PangoAttrList *retv) {\n  // Disable highlighting for normalize match, not supported atm.\n  if (config.normalize_match) {\n    return retv;\n  }\n  // Do a tokenized match.\n  if (tokens) {\n    for (int j = 0; tokens[j]; j++) {\n      GMatchInfo *gmi = NULL;\n      if (tokens[j]->invert) {\n        continue;\n      }\n      g_regex_match(tokens[j]->regex, input, G_REGEX_MATCH_PARTIAL, &gmi);\n      while (g_match_info_matches(gmi)) {\n        int count = g_match_info_get_match_count(gmi);\n        for (int index = (count > 1) ? 1 : 0; index < count; index++) {\n          int start, end;\n          g_match_info_fetch_pos(gmi, index, &start, &end);\n          helper_token_match_set_pango_attr_on_style(retv, start, end, th);\n        }\n        g_match_info_next(gmi, NULL);\n      }\n      g_match_info_free(gmi);\n    }\n  }\n  return retv;\n}\n\nint helper_token_match(rofi_int_matcher *const *tokens, const char *input) {\n  int match = TRUE;\n  // Do a tokenized match.\n  if (tokens) {\n    if (config.normalize_match) {\n      char *r = utf8_helper_simplify_string(input);\n      for (int j = 0; match && tokens[j]; j++) {\n        match = g_regex_match(tokens[j]->regex, r, 0, NULL);\n        match ^= tokens[j]->invert;\n      }\n      g_free(r);\n    } else {\n      for (int j = 0; match && tokens[j]; j++) {\n        match = g_regex_match(tokens[j]->regex, input, 0, NULL);\n        match ^= tokens[j]->invert;\n      }\n    }\n  }\n  return match;\n}\n\nint execute_generator(const char *cmd) {\n  char **args = NULL;\n  int argv = 0;\n  helper_parse_setup(config.run_command, &args, &argv, \"{cmd}\", cmd, (char *)0);\n\n  int fd = -1;\n  GError *error = NULL;\n  g_spawn_async_with_pipes(NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,\n                           NULL, NULL, &fd, NULL, &error);\n\n  if (error != NULL) {\n    char *msg = g_strdup_printf(\"Failed to execute: '%s'\\nError: '%s'\", cmd,\n                                error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n    fd = -1;\n  }\n  g_strfreev(args);\n  return fd;\n}\n\nint create_pid_file(const char *pidfile, gboolean kill_running) {\n  if (pidfile == NULL) {\n    return -1;\n  }\n\n  int fd = g_open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);\n  if (fd < 0) {\n    g_warning(\"Failed to create pid file: '%s'.\", pidfile);\n    return -1;\n  }\n  // Set it to close the File Descriptor on exit.\n  int flags = fcntl(fd, F_GETFD, NULL);\n  flags = flags | FD_CLOEXEC;\n  if (fcntl(fd, F_SETFD, flags, NULL) < 0) {\n    g_warning(\"Failed to set CLOEXEC on pidfile.\");\n    remove_pid_file(fd);\n    return -1;\n  }\n  // Try to get exclusive write lock on FD\n  int retv = flock(fd, LOCK_EX | LOCK_NB);\n  if (retv != 0) {\n    g_warning(\"Failed to set lock on pidfile: Rofi already running?\");\n    g_warning(\"Got error: %d %s\", retv, g_strerror(errno));\n    if (kill_running) {\n      char buffer[64] = {\n          0,\n      };\n      ssize_t l = read(fd, &(buffer[0]), 63);\n      if (l > 1) {\n        buffer[l] = 0;\n        pid_t pid = g_ascii_strtoll(buffer, NULL, 0);\n        kill(pid, SIGTERM);\n        while (1) {\n          retv = flock(fd, LOCK_EX | LOCK_NB);\n          if (retv == 0) {\n            break;\n          }\n          g_usleep(100);\n        }\n      }\n      remove_pid_file(fd);\n      return create_pid_file(pidfile, FALSE);\n    }\n\n    remove_pid_file(fd);\n    return -1;\n  }\n  if (ftruncate(fd, (off_t)0) == 0) {\n    // Write pid, not needed, but for completeness sake.\n    char buffer[64];\n    int length = snprintf(buffer, 64, \"%i\", getpid());\n    ssize_t l = 0;\n    while (l < length) {\n      l += write(fd, &buffer[l], length - l);\n    }\n  }\n  return fd;\n}\n\nvoid remove_pid_file(int fd) {\n  if (fd >= 0) {\n    if (close(fd)) {\n      g_warning(\"Failed to close pidfile: '%s'\", g_strerror(errno));\n    }\n  }\n}\n\ngboolean helper_validate_font(PangoFontDescription *pfd, const char *font) {\n  const char *fam = pango_font_description_get_family(pfd);\n  int size = pango_font_description_get_size(pfd);\n  if (fam == NULL || size == 0) {\n    g_debug(\"Pango failed to parse font: '%s'\", font);\n    g_debug(\"Got family: <b>%s</b> at size: <b>%d</b>\", fam ? fam : \"{unknown}\",\n            size);\n    return FALSE;\n  }\n  return TRUE;\n}\n\n/**\n * Do some input validation, especially the first few could break things.\n * It is good to catch them beforehand.\n *\n * This functions exits the program with 1 when it finds an invalid\n * configuration.\n */\nint config_sanity_check(void) {\n  int found_error = FALSE;\n  GString *msg =\n      g_string_new(\"<big><b>The configuration failed to validate:</b></big>\\n\");\n\n  if (config.sorting_method) {\n    if (g_strcmp0(config.sorting_method, \"normal\") == 0) {\n      config.sorting_method_enum = SORT_NORMAL;\n    } else if (g_strcmp0(config.sorting_method, \"levenshtein\") == 0) {\n      config.sorting_method_enum = SORT_NORMAL;\n    } else if (g_strcmp0(config.sorting_method, \"fzf\") == 0) {\n      config.sorting_method_enum = SORT_FZF;\n    } else {\n      g_string_append_printf(\n          msg,\n          \"\\t<b>config.sorting_method</b>=%s is not a valid sorting \"\n          \"strategy.\\nValid options are: normal or fzf.\\n\",\n          config.sorting_method);\n      found_error = 1;\n    }\n  }\n\n  if (config.matching) {\n    char **strv = g_strsplit(config.matching, \",\", 0);\n    if (strv) {\n      int matching_method_index = 0;\n      for (char **str = strv; *str && matching_method_index < MM_NUM_MATCHERS;\n           str++) {\n        gboolean found = FALSE;\n        for (unsigned i = 0;\n             i < MM_NUM_MATCHERS && matching_method_index < MM_NUM_MATCHERS;\n             i++) {\n          if (g_ascii_strcasecmp(*str, MatchingMethodStr[i]) == 0) {\n            MatchingMethodEnabled[matching_method_index] = i;\n            matching_method_index++;\n            NUMMatchingMethodEnabled = matching_method_index;\n            if (matching_method_index == MM_NUM_MATCHERS) {\n              found_error = 1;\n              g_string_append_printf(msg,\n                                     \"\\t<b>config.matching</b> = %s to many \"\n                                     \"matching options enabled.\\n\",\n                                     config.matching);\n            }\n            found = TRUE;\n          }\n        }\n        if (!found) {\n          g_string_append_printf(msg,\n                                 \"\\t<b>config.matching</b>=%s is not a valid \"\n                                 \"matching strategy.\\nValid options are: glob, \"\n                                 \"regex, fuzzy, prefix or normal.\\n\",\n                                 *str);\n          found_error = 1;\n        }\n      }\n      config.matching_method = MatchingMethodEnabled[0];\n      g_strfreev(strv);\n    }\n  }\n\n  if (config.element_height < 1) {\n    g_string_append_printf(msg,\n                           \"\\t<b>config.element_height</b>=%d is invalid. An \"\n                           \"element needs to be at least 1 line high.\\n\",\n                           config.element_height);\n    config.element_height = 1;\n    found_error = TRUE;\n  }\n  if (!(config.location >= 0 && config.location <= 8)) {\n    g_string_append_printf(msg,\n                           \"\\t<b>config.location</b>=%d is invalid. Value \"\n                           \"should be between %d and %d.\\n\",\n                           config.location, 0, 8);\n    config.location = WL_CENTER;\n    found_error = 1;\n  }\n\n#ifdef ENABLE_XCB\n  // Check size\n  {\n    workarea mon;\n    if (config.backend == DISPLAY_XCB && !monitor_active(&mon)) {\n      const char *name = config.monitor;\n      if (name && name[0] == '-') {\n        int index = name[1] - '0';\n        if (index < 5 && index > 0) {\n          name = monitor_position_entries[index - 1];\n        }\n      }\n      g_string_append_printf(\n          msg, \"\\t<b>config.monitor</b>=%s Could not find monitor.\\n\", name);\n      found_error = TRUE;\n    }\n  }\n#endif\n\n  if (g_strcmp0(config.monitor, \"-3\") == 0) {\n    // On -3, set to location 1.\n    config.location = 1;\n  }\n\n  if (found_error) {\n    g_string_append(msg, \"Please update your configuration.\");\n    rofi_add_error_message(msg);\n    return TRUE;\n  }\n\n  g_string_free(msg, TRUE);\n  return FALSE;\n}\n\nchar *rofi_expand_path(const char *input) {\n  if (input == NULL ) {\n    return NULL;\n  }\n  char **str = g_strsplit(input, G_DIR_SEPARATOR_S, -1);\n  for (unsigned int i = 0; str && str[i]; i++) {\n    // Replace ~ with current user homedir.\n    if (str[i][0] == '~' && str[i][1] == '\\0') {\n      g_free(str[i]);\n      str[i] = g_strdup(g_get_home_dir());\n    }\n    // If other user, ask getpwnam.\n    else if (str[i][0] == '~') {\n      struct passwd *p = getpwnam(&(str[i][1]));\n      if (p != NULL) {\n        g_free(str[i]);\n        str[i] = g_strdup(p->pw_dir);\n      }\n    } else if (i == 0) {\n      char *s = str[i];\n      if (input[0] == G_DIR_SEPARATOR) {\n        str[i] = g_strdup_printf(\"%s%s\", G_DIR_SEPARATOR_S, s);\n        g_free(s);\n      }\n    }\n  }\n  char *retv = g_build_filenamev(str);\n  g_strfreev(str);\n  return retv;\n}\n\n/** Return the minimum value of a,b,c */\n#define MIN3(a, b, c)                                                          \\\n  ((a) < (b) ? ((a) < (c) ? (a) : (c)) : ((b) < (c) ? (b) : (c)))\n\nunsigned int levenshtein(const char *needle, const glong needlelen,\n                         const char *haystack, const glong haystacklen,\n                         int case_sensitive) {\n  if (needlelen == G_MAXLONG) {\n    // String to long, we cannot handle this.\n    return UINT_MAX;\n  }\n  unsigned int column[needlelen + 1];\n  for (glong y = 0; y < needlelen; y++) {\n    column[y] = y;\n  }\n  // Removed out of the loop, otherwise static code analyzers think it is\n  // unset.. silly but true. old loop: for ( glong y = 0; y <= needlelen; y++)\n  column[needlelen] = needlelen;\n  for (glong x = 1; x <= haystacklen; x++) {\n    const char *needles = needle;\n    column[0] = x;\n    gunichar haystackc = g_utf8_get_char(haystack);\n    if (!case_sensitive) {\n      haystackc = g_unichar_tolower(haystackc);\n    }\n    for (glong y = 1, lastdiag = x - 1; y <= needlelen; y++) {\n      gunichar needlec = g_utf8_get_char(needles);\n      if (!case_sensitive) {\n        needlec = g_unichar_tolower(needlec);\n      }\n      unsigned int olddiag = column[y];\n      column[y] = MIN3(column[y] + 1, column[y - 1] + 1,\n                       lastdiag + (needlec == haystackc ? 0 : 1));\n      lastdiag = olddiag;\n      needles = g_utf8_next_char(needles);\n    }\n    haystack = g_utf8_next_char(haystack);\n  }\n  return column[needlelen];\n}\n\nchar *rofi_latin_to_utf8_strdup(const char *input, gssize length) {\n  gsize slength = 0;\n  return g_convert_with_fallback(input, length, \"UTF-8\", \"latin1\", \"\\uFFFD\",\n                                 NULL, &slength, NULL);\n}\n\nchar *rofi_force_utf8(const gchar *data, ssize_t length) {\n  if (data == NULL) {\n    return NULL;\n  }\n  const char *end;\n  GString *string;\n\n  if (g_utf8_validate(data, length, &end)) {\n    return g_memdup2(data, length + 1);\n  }\n  string = g_string_sized_new(length + 16);\n\n  do {\n    /* Valid part of the string */\n    g_string_append_len(string, data, end - data);\n    /* Replacement character */\n    g_string_append(string, \"\\uFFFD\");\n    length -= (end - data) + 1;\n    data = end + 1;\n  } while (!g_utf8_validate(data, length, &end));\n\n  if (length) {\n    g_string_append_len(string, data, length);\n  }\n\n  return g_string_free(string, FALSE);\n}\n\n/****\n * FZF like scorer\n */\n\n/** Max length of input to score. */\n#define FUZZY_SCORER_MAX_LENGTH 256\n/** minimum score */\n#define MIN_SCORE (INT_MIN / 2)\n/** Leading gap score */\n#define LEADING_GAP_SCORE -4\n/** gap score */\n#define GAP_SCORE -5\n/** start of word score */\n#define WORD_START_SCORE 50\n/** non-word score */\n#define NON_WORD_SCORE 40\n/** CamelCase score */\n#define CAMEL_SCORE (WORD_START_SCORE + GAP_SCORE - 1)\n/** Consecutive score */\n#define CONSECUTIVE_SCORE (WORD_START_SCORE + GAP_SCORE)\n/** non-start multiplier */\n#define PATTERN_NON_START_MULTIPLIER 1\n/** start multiplier */\n#define PATTERN_START_MULTIPLIER 2\n\n/**\n * Character classification.\n */\nenum CharClass {\n  /* Lower case */\n  LOWER,\n  /* Upper case */\n  UPPER,\n  /* Number */\n  DIGIT,\n  /* non word character */\n  NON_WORD\n};\n\n/**\n * @param c The character to determine class of\n *\n * @returns the class of the character c.\n */\nstatic enum CharClass rofi_scorer_get_character_class(gunichar c) {\n  if (g_unichar_islower(c)) {\n    return LOWER;\n  }\n  if (g_unichar_isupper(c)) {\n    return UPPER;\n  }\n  if (g_unichar_isdigit(c)) {\n    return DIGIT;\n  }\n  return NON_WORD;\n}\n\n/**\n * @param prev The previous character.\n * @param curr The current character\n *\n * Scrore the transition.\n *\n * @returns score of the transition.\n */\nstatic int rofi_scorer_get_score_for(enum CharClass prev, enum CharClass curr) {\n  if (prev == NON_WORD && curr != NON_WORD) {\n    return WORD_START_SCORE;\n  }\n  if ((prev == LOWER && curr == UPPER) || (prev != DIGIT && curr == DIGIT)) {\n    return CAMEL_SCORE;\n  }\n  if (curr == NON_WORD) {\n    return NON_WORD_SCORE;\n  }\n  return 0;\n}\n\nint rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str,\n                               glong slen, int case_sensitive) {\n  if (slen > FUZZY_SCORER_MAX_LENGTH) {\n    return -MIN_SCORE;\n  }\n  glong pi, si;\n  // whether we are aligning the first character of pattern\n  gboolean pfirst = TRUE;\n  // whether the start of a word in pattern\n  gboolean pstart = TRUE;\n  // score for each position\n  int *score = g_malloc_n(slen, sizeof(int));\n  // dp[i]: maximum value by aligning pattern[0..pi] to str[0..si]\n  int *dp = g_malloc_n(slen, sizeof(int));\n  // uleft: value of the upper left cell; ulefts: maximum value of uleft and\n  // cells on the left. The arbitrary initial values suppress warnings.\n  int uleft = 0, ulefts = 0, left, lefts;\n  const gchar *pit = pattern, *sit;\n  enum CharClass prev = NON_WORD;\n  for (si = 0, sit = str; si < slen; si++, sit = g_utf8_next_char(sit)) {\n    enum CharClass cur = rofi_scorer_get_character_class(g_utf8_get_char(sit));\n    score[si] = rofi_scorer_get_score_for(prev, cur);\n    prev = cur;\n    dp[si] = MIN_SCORE;\n  }\n  for (pi = 0; pi < plen; pi++, pit = g_utf8_next_char(pit)) {\n    gunichar pc = g_utf8_get_char(pit), sc;\n    if (g_unichar_isspace(pc)) {\n      pstart = TRUE;\n      continue;\n    }\n    lefts = MIN_SCORE;\n    for (si = 0, sit = str; si < slen; si++, sit = g_utf8_next_char(sit)) {\n      left = dp[si];\n      lefts = MAX(lefts + GAP_SCORE, left);\n      sc = g_utf8_get_char(sit);\n      if (case_sensitive ? pc == sc\n                         : g_unichar_tolower(pc) == g_unichar_tolower(sc)) {\n        int t = score[si] * (pstart ? PATTERN_START_MULTIPLIER\n                                    : PATTERN_NON_START_MULTIPLIER);\n        dp[si] = pfirst ? LEADING_GAP_SCORE * si + t\n                        : MAX(uleft + CONSECUTIVE_SCORE, ulefts + t);\n      } else {\n        dp[si] = MIN_SCORE;\n      }\n      uleft = left;\n      ulefts = lefts;\n    }\n    pfirst = pstart = FALSE;\n  }\n  lefts = MIN_SCORE;\n  for (si = 0; si < slen; si++) {\n    lefts = MAX(lefts + GAP_SCORE, dp[si]);\n  }\n  g_free(score);\n  g_free(dp);\n  return -lefts;\n}\n\n/**\n * @param a    UTF-8 string to compare\n * @param b    UTF-8 string to compare\n * @param n    Maximum number of characters to compare\n *\n * Compares the `G_NORMALIZE_ALL_COMPOSE` forms of the two strings.\n *\n * @returns less than, equal to, or greater than zero if the first `n`\n * characters (not bytes) of `a` are found, respectively, to be less than, to\n * match, or be greater than the first `n` characters (not bytes) of `b`.\n */\nint utf8_strncmp(const char *a, const char *b, size_t n) {\n  char *na = g_utf8_normalize(a, -1, G_NORMALIZE_ALL_COMPOSE);\n  char *nb = g_utf8_normalize(b, -1, G_NORMALIZE_ALL_COMPOSE);\n  *g_utf8_offset_to_pointer(na, n) = '\\0';\n  *g_utf8_offset_to_pointer(nb, n) = '\\0';\n  int r = g_utf8_collate(na, nb);\n  g_free(na);\n  g_free(nb);\n  return r;\n}\n\ngboolean helper_execute(const char *wd, char **args, const char *error_precmd,\n                        const char *error_cmd,\n                        RofiHelperExecuteContext *context) {\n  gboolean retv = TRUE;\n  GError *error = NULL;\n\n  GSpawnChildSetupFunc child_setup = NULL;\n  gpointer user_data = NULL;\n\n  display_startup_notification(context, &child_setup, &user_data);\n\n  g_spawn_async(wd, args, NULL, G_SPAWN_SEARCH_PATH, child_setup, user_data,\n                NULL, &error);\n  if (error != NULL) {\n    char *msg = g_strdup_printf(\"Failed to execute: '%s%s'\\nError: '%s'\",\n                                error_precmd, error_cmd, error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n    retv = FALSE;\n  }\n\n  // Free the args list.\n  g_strfreev(args);\n  return retv;\n}\n\ngboolean helper_execute_command(const char *wd, const char *cmd,\n                                gboolean run_in_term,\n                                RofiHelperExecuteContext *context) {\n  char **args = NULL;\n  int argc = 0;\n\n  if (run_in_term) {\n    helper_parse_setup(config.run_shell_command, &args, &argc, \"{cmd}\", cmd,\n                       (char *)0);\n  } else {\n    helper_parse_setup(config.run_command, &args, &argc, \"{cmd}\", cmd,\n                       (char *)0);\n  }\n\n  if (args == NULL) {\n    return FALSE;\n  }\n\n  if (context != NULL) {\n    if (context->name == NULL) {\n      context->name = args[0];\n    }\n    if (context->binary == NULL) {\n      context->binary = args[0];\n    }\n    if (context->description == NULL) {\n      gsize l = strlen(\"Launching '' via rofi\") + strlen(cmd) + 1;\n      gchar *description = g_newa(gchar, l);\n\n      g_snprintf(description, l, \"Launching '%s' via rofi\", cmd);\n      context->description = description;\n    }\n    if (context->command == NULL) {\n      context->command = cmd;\n    }\n  }\n\n  return helper_execute(wd, args, \"\", cmd, context);\n}\n\nstatic char *helper_get_theme_path_check_file(const char *filename,\n                                              const char *parent_file) {\n\n  // Check if absolute path.\n  if (g_path_is_absolute(filename)) {\n    g_debug(\"Opening theme, path is absolute: %s\", filename);\n    if (g_file_test(filename, G_FILE_TEST_EXISTS)) {\n      return g_strdup(filename);\n    }\n    g_debug(\"Opening theme, path is absolute but does not exists: %s\",\n            filename);\n  } else {\n    if (parent_file != NULL) {\n      // If no absolute path specified, expand it.\n      char *basedir = g_path_get_dirname(parent_file);\n      char *path = g_build_filename(basedir, filename, NULL);\n      g_free(basedir);\n      g_debug(\"Opening theme, check in dir where file is included: %s\", path);\n      if (g_file_test(path, G_FILE_TEST_EXISTS)) {\n        return path;\n      }\n      g_debug(\"Opening theme, file does not exists in dir where file is \"\n              \"included: %s\\n\",\n              filename);\n    }\n  }\n  // Check config's themes directory.\n  const char *cpath = g_get_user_config_dir();\n  if (cpath) {\n    char *themep = g_build_filename(cpath, \"rofi\", \"themes\", filename, NULL);\n    g_debug(\"Opening theme, testing: %s\", themep);\n    if (themep && g_file_test(themep, G_FILE_TEST_EXISTS)) {\n      return themep;\n    }\n    g_free(themep);\n  }\n  // Check config directory.\n  if (cpath) {\n    char *themep = g_build_filename(cpath, \"rofi\", filename, NULL);\n    g_debug(\"Opening theme, testing: %s\", themep);\n    if (g_file_test(themep, G_FILE_TEST_EXISTS)) {\n      return themep;\n    }\n    g_free(themep);\n  }\n  const char *datadir = g_get_user_data_dir();\n  if (datadir) {\n    char *theme_path =\n        g_build_filename(datadir, \"rofi\", \"themes\", filename, NULL);\n    if (theme_path) {\n      g_debug(\"Opening theme, testing: %s\", theme_path);\n      if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {\n        return theme_path;\n      }\n      g_free(theme_path);\n    }\n  }\n\n  const gchar *const *system_data_dirs = g_get_system_data_dirs();\n  if (system_data_dirs) {\n    for (uint_fast32_t i = 0; system_data_dirs[i] != NULL; i++) {\n      const char *const sdatadir = system_data_dirs[i];\n      g_debug(\"Opening theme directory: %s\", sdatadir);\n      char *theme_path =\n          g_build_filename(sdatadir, \"rofi\", \"themes\", filename, NULL);\n      if (theme_path) {\n        g_debug(\"Opening theme, testing: %s\", theme_path);\n        if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {\n          return theme_path;\n        }\n        g_free(theme_path);\n      }\n    }\n  }\n\n  char *theme_path = g_build_filename(THEME_DIR, filename, NULL);\n  if (theme_path) {\n    g_debug(\"Opening theme, testing: %s\", theme_path);\n    if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {\n      return theme_path;\n    }\n    g_free(theme_path);\n  }\n  return NULL;\n}\n\nchar *helper_get_theme_path(const char *file, const char **ext,\n                            const char *parent_file) {\n\n  char *filename = rofi_expand_path(file);\n  g_debug(\"Opening theme, testing: %s\\n\", filename);\n  if (g_path_is_absolute(filename)) {\n    g_debug(\"Opening theme, path is absolute: %s\", filename);\n    if (g_file_test(filename, G_FILE_TEST_EXISTS)) {\n      return filename;\n    }\n  }\n  gboolean ext_found = FALSE;\n  for (const char **i = ext; *i != NULL; i++) {\n    if (g_str_has_suffix(file, *i)) {\n      ext_found = TRUE;\n      break;\n    }\n  }\n  if (ext_found) {\n    filename = rofi_expand_path(file);\n\n    char *retv = helper_get_theme_path_check_file(filename, parent_file);\n    if (retv) {\n      g_free(filename);\n      return retv;\n    }\n  } else {\n    g_assert_nonnull(ext[0]);\n    // Iterate through extensions.\n    char *temp = filename;\n    for (const char **i = ext; *i != NULL; i++) {\n      filename = g_strconcat(temp, *i, NULL);\n      char *retv = helper_get_theme_path_check_file(filename, parent_file);\n      if (retv) {\n        g_free(filename);\n        g_free(temp);\n        return retv;\n      }\n    }\n    g_free(temp);\n  }\n\n  return filename;\n}\n\nstatic gboolean parse_pair(char *input, rofi_range_pair *item) {\n  // Skip leading blanks.\n  while (input != NULL && isblank(*input)) {\n    ++input;\n  }\n\n  if (input == NULL) {\n    return FALSE;\n  }\n\n  const char *sep[] = {\"-\", \":\"};\n  int pythonic = (strchr(input, ':') || input[0] == '-') ? 1 : 0;\n  int index = 0;\n\n  for (char *token = strsep(&input, sep[pythonic]); token != NULL;\n       token = strsep(&input, sep[pythonic])) {\n    if (index == 0) {\n      item->start = item->stop = (int)strtol(token, NULL, 10);\n      index++;\n      continue;\n    }\n\n    if (token[0] == '\\0') {\n      item->stop = -1;\n      continue;\n    }\n\n    item->stop = (int)strtol(token, NULL, 10);\n    if (pythonic) {\n      --item->stop;\n    }\n  }\n  return TRUE;\n}\nvoid parse_ranges(char *input, rofi_range_pair **list, unsigned int *length) {\n  char *endp;\n  if (input == NULL) {\n    return;\n  }\n  const char *const sep = \",\";\n  for (char *token = strtok_r(input, sep, &endp); token != NULL;\n       token = strtok_r(NULL, sep, &endp)) {\n    // Make space.\n    *list =\n        g_realloc((*list), ((*length) + 1) * sizeof(struct rofi_range_pair));\n    // Parse a single pair.\n    if (parse_pair(token, &((*list)[*length]))) {\n      (*length)++;\n    }\n  }\n}\n\nint parse_case_sensitivity(const char *input) {\n  int case_sensitive = config.case_sensitive;\n  if (config.case_smart) {\n    // By default case is false, unless the search query has a\n    // uppercase in it?\n    case_sensitive = FALSE;\n    const char *end;\n    if (g_utf8_validate(input, -1, &end)) {\n      for (const char *c = (input); !case_sensitive && c != NULL && *c;\n           c = g_utf8_next_char(c)) {\n        gunichar uc = g_utf8_get_char(c);\n        if (g_unichar_isupper(uc)) {\n          case_sensitive = TRUE;\n        }\n      }\n    }\n  }\n\n  return case_sensitive;\n}\n\nvoid rofi_output_formatted_line(const char *format, const char *string,\n                                int selected_line, const char *filter) {\n  for (int i = 0; format && format[i]; i++) {\n    if (format[i] == 'i') {\n      fprintf(stdout, \"%d\", selected_line);\n    } else if (format[i] == 'd') {\n      fprintf(stdout, \"%d\", (selected_line + 1));\n    } else if (format[i] == 's') {\n      fputs(string, stdout);\n    } else if (format[i] == 'p') {\n      char *esc = NULL;\n      pango_parse_markup(string, -1, 0, NULL, &esc, NULL, NULL);\n      if (esc) {\n        fputs(esc, stdout);\n        g_free(esc);\n      } else {\n        fputs(\"invalid string\", stdout);\n      }\n    } else if (format[i] == 'q') {\n      char *quote = g_shell_quote(string);\n      fputs(quote, stdout);\n      g_free(quote);\n    } else if (format[i] == 'f') {\n      if (filter) {\n        fputs(filter, stdout);\n      }\n    } else if (format[i] == 'F') {\n      if (filter) {\n        char *quote = g_shell_quote(filter);\n        fputs(quote, stdout);\n        g_free(quote);\n      }\n    } else {\n      fputc(format[i], stdout);\n    }\n  }\n  fputc('\\n', stdout);\n  fflush(stdout);\n}\n\nstatic gboolean helper_eval_cb2(const GMatchInfo *info, GString *res,\n                                gpointer data) {\n  gchar *match;\n  // Get the match\n  int num_match = g_match_info_get_match_count(info);\n  // Just {text} This is inside () 5.\n  if (num_match == 5) {\n    match = g_match_info_fetch(info, 4);\n    if (match != NULL) {\n      // Lookup the match, so we can replace it.\n      gchar *r = g_hash_table_lookup((GHashTable *)data, match);\n      if (r != NULL) {\n        // Append the replacement to the string.\n        g_string_append(res, r);\n      }\n      // Free match.\n      g_free(match);\n    }\n  }\n  // {} with [] guard around it.\n  else if (num_match == 4) {\n    match = g_match_info_fetch(info, 2);\n    if (match != NULL) {\n      // Lookup the match, so we can replace it.\n      gchar *r = g_hash_table_lookup((GHashTable *)data, match);\n      if (r != NULL) {\n        // Add (optional) prefix\n        gchar *prefix = g_match_info_fetch(info, 1);\n        g_string_append(res, prefix);\n        g_free(prefix);\n        // Append the replacement to the string.\n        g_string_append(res, r);\n        // Add (optional) postfix\n        gchar *post = g_match_info_fetch(info, 3);\n        g_string_append(res, post);\n        g_free(post);\n      }\n      // Free match.\n      g_free(match);\n    }\n  }\n  // Else we have an invalid match.\n  // Continue replacement.\n  return FALSE;\n}\n\nchar *helper_string_replace_if_exists(char *string, ...) {\n  GHashTable *h;\n  h = g_hash_table_new(g_str_hash, g_str_equal);\n  va_list ap;\n  va_start(ap, string);\n  // Add list from variable arguments.\n  while (1) {\n    char *key = va_arg(ap, char *);\n    if (key == (char *)0) {\n      break;\n    }\n    char *value = va_arg(ap, char *);\n    g_hash_table_insert(h, key, value);\n  }\n  char *retv = helper_string_replace_if_exists_v(string, h);\n  va_end(ap);\n  // Destroy key-value storage.\n  g_hash_table_destroy(h);\n  return retv;\n}\n/**\n * @param string The string with elements to be replaced\n * @param h      Hash table with set of {key}, value that will be replaced,\n * terminated by  a NULL\n *\n * Items {key} are replaced by the value if '{key}' is passed as key/value\n * pair, otherwise removed from string. If the {key} is in between []  all the\n * text between [] are removed if {key} is not found. Otherwise key is\n * replaced and [ & ] removed.\n *\n * This allows for optional replacement, f.e.   '{ssh-client} [-t  {title}] -e\n * \"{cmd}\"' the '-t {title}' is only there if {title} is set.\n *\n * @returns a new string with the keys replaced.\n */\nchar *helper_string_replace_if_exists_v(char *string, GHashTable *h) {\n  GError *error = NULL;\n  char *res = NULL;\n\n  // Replace hits within {-\\w+}.\n  GRegex *reg = g_regex_new(\"\\\\[(.*)({[-\\\\w]+})(.*)\\\\]|({[\\\\w-]+})\",\n                            G_REGEX_UNGREEDY, 0, &error);\n  if (error == NULL) {\n    res =\n        g_regex_replace_eval(reg, string, -1, 0, 0, helper_eval_cb2, h, &error);\n  }\n  // Free regex.\n  g_regex_unref(reg);\n  // Throw error if shell parsing fails.\n  if (error != NULL) {\n    char *msg = g_strdup_printf(\"Failed to parse: '%s'\\nError: '%s'\", string,\n                                error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n    g_free(res);\n    return NULL;\n  }\n  return res;\n}\n"
  },
  {
    "path": "source/history.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"config.h\"\n\n#include \"history.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include <errno.h>\n#include <glib.h>\n#include <glib/gstdio.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n/**\n * History element\n */\ntypedef struct __element {\n  /** Index in history */\n  long int index;\n  /** Entry */\n  char *name;\n} _element;\n\nstatic int __element_sort_func(const void *ea, const void *eb,\n                               void *data __attribute__((unused))) {\n  _element *a = *(_element **)ea;\n  _element *b = *(_element **)eb;\n  return b->index - a->index;\n}\n\nstatic void __history_write_element_list(FILE *fd, _element **list,\n                                         unsigned int length) {\n  if (list == NULL || length == 0) {\n    return;\n  }\n  // Sort the list before writing out.\n  g_qsort_with_data(list, length, sizeof(_element *), __element_sort_func,\n                    NULL);\n\n  // Get minimum index.\n  int min_value = list[length - 1]->index;\n\n  // Set the max length of the list.\n  length =\n      (length > config.max_history_size) ? config.max_history_size : length;\n\n  // Write out entries.\n  for (unsigned int iter = 0; iter < length; iter++) {\n    fprintf(fd, \"%ld %s\\n\", list[iter]->index - min_value, list[iter]->name);\n  }\n}\n\nstatic char **__history_get_element_list_fields(FILE *fd,\n                                                unsigned int *length) {\n  unsigned int real_length = 0;\n  char **retv = NULL;\n  ;\n  if (length == NULL) {\n    return NULL;\n  }\n  *length = 0;\n\n  if (fd == NULL) {\n    return NULL;\n  }\n  char *buffer = NULL;\n  size_t buffer_length = 0;\n  ssize_t l = 0;\n  while ((l = getline(&buffer, &buffer_length, fd)) > 0) {\n    // Jump to the first space.\n    const char *start = strchr(buffer, ' ');\n    // not found, skip.\n    if (start == NULL) {\n      continue;\n    }\n    start++;\n    // remove trailing \\n\n    buffer[l - 1] = '\\0';\n    if (real_length < (*length + 2)) {\n      real_length += 15;\n      // Resize and check.\n      retv = g_realloc(retv, (real_length) * sizeof(char *));\n    }\n    // Parse the number of times.\n    retv[(*length)] = g_strndup(start, l - 1 - (start - buffer));\n    // Force trailing '\\0'\n    retv[(*length) + 1] = NULL;\n\n    (*length)++;\n  }\n  // Don't use buffer_length to check, as static\n  // code analysis fails on this.\n  if (buffer != NULL) {\n    g_free(buffer);\n  }\n  return retv;\n}\n\nstatic _element **__history_get_element_list(FILE *fd, unsigned int *length) {\n  unsigned int real_length = 0;\n  _element **retv = NULL;\n\n  if (length == NULL) {\n    return NULL;\n  }\n  *length = 0;\n\n  if (fd == NULL) {\n    return NULL;\n  }\n  char *buffer = NULL;\n  size_t buffer_length = 0;\n  ssize_t l = 0;\n  while ((l = getline(&buffer, &buffer_length, fd)) > 0) {\n    char *start = NULL;\n    // Skip empty lines.\n    if (l <= 1) {\n      continue;\n    }\n\n    long int index = strtol(buffer, &start, 10);\n    if (start == buffer || *start == '\\0') {\n      continue;\n    }\n    start++;\n    if ((l - (start - buffer)) < 2) {\n      continue;\n    }\n    if (real_length < (*length + 2)) {\n      real_length += 15;\n      // Resize and check.\n      retv = g_realloc(retv, (real_length) * sizeof(_element *));\n    }\n\n    retv[(*length)] = g_malloc(sizeof(_element));\n\n    // remove trailing \\n\n    buffer[l - 1] = '\\0';\n    // Parse the number of times.\n    retv[(*length)]->index = index;\n    retv[(*length)]->name = g_strndup(start, l - 1 - (start - buffer));\n    // Force trailing '\\0'\n    retv[(*length) + 1] = NULL;\n\n    (*length)++;\n  }\n  if (buffer != NULL) {\n    free(buffer);\n    buffer = NULL;\n  }\n  return retv;\n}\n\nvoid history_set(const char *filename, const char *entry) {\n  if (config.disable_history) {\n    return;\n  }\n\n  // Check if program should be ignored\n  // TODO: This code does not! belong here.\n  for (char *checked_prefix = strtok(config.ignored_prefixes, \";\");\n       checked_prefix != NULL; checked_prefix = strtok(NULL, \";\")) {\n    // For each ignored prefix\n\n    while (g_unichar_isspace(g_utf8_get_char(checked_prefix))) {\n      checked_prefix = g_utf8_next_char(\n          checked_prefix); // Some users will probably want \"; \" as their\n                           // separator for aesthetics.\n    }\n\n    if (g_str_has_prefix(entry, checked_prefix)) {\n      return;\n    }\n  }\n\n  int found = 0;\n  unsigned int curr = 0;\n  unsigned int length = 0;\n  _element **list = NULL;\n  // Open file for reading and writing.\n  FILE *fd = g_fopen(filename, \"r\");\n  if (fd != NULL) {\n    // Get list.\n    list = __history_get_element_list(fd, &length);\n    // Close file, if fails let user know on stderr.\n    if (fclose(fd) != 0) {\n      g_warning(\"Failed to close history file: %s\", g_strerror(errno));\n    }\n  }\n  // Look if the entry exists.\n  for (unsigned int iter = 0; !found && iter < length; iter++) {\n    if (strcmp(list[iter]->name, entry) == 0) {\n      curr = iter;\n      found = 1;\n    }\n  }\n\n  if (found) {\n    // If exists, increment list index number\n    list[curr]->index++;\n  } else {\n    // If not exists, add it.\n    // Increase list by one\n    list = g_realloc(list, (length + 2) * sizeof(_element *));\n    list[length] = g_malloc(sizeof(_element));\n    // Copy name\n    if (list[length] != NULL) {\n      list[length]->name = g_strdup(entry);\n      // set # hits\n      list[length]->index = 1;\n\n      length++;\n      list[length] = NULL;\n    }\n  }\n\n  fd = fopen(filename, \"w\");\n  if (fd == NULL) {\n    g_warning(\"Failed to open file: %s\", g_strerror(errno));\n  } else {\n    // Write list.\n    __history_write_element_list(fd, list, length);\n    // Close file, if fails let user know on stderr.\n    if (fclose(fd) != 0) {\n      g_warning(\"Failed to close history file: %s\", g_strerror(errno));\n    }\n  }\n  // Free the list.\n  for (unsigned int iter = 0; iter < length; iter++) {\n    g_free(list[iter]->name);\n    g_free(list[iter]);\n  }\n  g_free(list);\n}\n\nvoid history_remove(const char *filename, const char *entry) {\n  if (config.disable_history) {\n    return;\n  }\n  _element **list = NULL;\n  int found = 0;\n  unsigned int curr = 0;\n  unsigned int length = 0;\n  // Open file for reading and writing.\n  FILE *fd = g_fopen(filename, \"r\");\n  if (fd == NULL) {\n    g_warning(\"Failed to open file: %s\", g_strerror(errno));\n    return;\n  }\n  // Get list.\n  list = __history_get_element_list(fd, &length);\n\n  // Close file, if fails let user know on stderr.\n  if (fclose(fd) != 0) {\n    g_warning(\"Failed to close history file: %s\", g_strerror(errno));\n  }\n  // Find entry.\n  for (unsigned int iter = 0; !found && iter < length; iter++) {\n    if (strcmp(list[iter]->name, entry) == 0) {\n      curr = iter;\n      found = 1;\n    }\n  }\n\n  // If found, remove it and write out new file.\n  if (found) {\n    // Remove the entry.\n    g_free(list[curr]->name);\n    g_free(list[curr]);\n    // Swap last to here (if list is size 1, we just swap empty sets).\n    list[curr] = list[length - 1];\n    // Empty last.\n    list[length - 1] = NULL;\n    length--;\n\n    fd = g_fopen(filename, \"w\");\n    // Clear list.\n    if (fd != NULL) {\n      // Write list.\n      __history_write_element_list(fd, list, length);\n      // Close file, if fails let user know on stderr.\n      if (fclose(fd) != 0) {\n        g_warning(\"Failed to close history file: %s\", g_strerror(errno));\n      }\n    } else {\n      g_warning(\"Failed to open file: %s\", g_strerror(errno));\n    }\n  }\n\n  // Free the list.\n  for (unsigned int iter = 0; iter < length; iter++) {\n    g_free(list[iter]->name);\n    g_free(list[iter]);\n  }\n  if (list != NULL) {\n    g_free(list);\n  }\n}\n\nchar **history_get_list(const char *filename, unsigned int *length) {\n  *length = 0;\n\n  if (config.disable_history) {\n    return NULL;\n  }\n  char **retv = NULL;\n  // Open file.\n  FILE *fd = g_fopen(filename, \"r\");\n  if (fd == NULL) {\n    // File that does not exists is not an error, so ignore it.\n    // Everything else? panic.\n    if (errno != ENOENT) {\n      g_warning(\"Failed to open file: %s\", g_strerror(errno));\n    }\n    return NULL;\n  }\n  // Get list.\n  retv = __history_get_element_list_fields(fd, length);\n\n  // Close file, if fails let user know on stderr.\n  if (fclose(fd) != 0) {\n    g_warning(\"Failed to close history file: %s\", g_strerror(errno));\n  }\n  return retv;\n}\n"
  },
  {
    "path": "source/keyb.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"keyb.h\"\n#include \"config.h\"\n#include \"rofi.h\"\n#include \"xrmoptions.h\"\n#include <glib.h>\n#include <nkutils-bindings.h>\n#include <string.h>\n\ntypedef struct {\n  guint id;\n  guint scope;\n  char *name;\n  char *binding;\n  char *comment;\n} ActionBindingEntry;\n\n/**\n * Data structure holding all the action keybinding.\n */\nActionBindingEntry rofi_bindings[] = {\n    {.id = PASTE_PRIMARY,\n     .name = \"kb-primary-paste\",\n     .binding = \"Control+V,Shift+Insert\",\n     .comment = \"Paste primary selection\"},\n    {.id = PASTE_SECONDARY,\n     .name = \"kb-secondary-paste\",\n     .binding = \"Control+v,Insert\",\n     .comment = \"Paste clipboard\"},\n    {.id = COPY_SECONDARY,\n     .name = \"kb-secondary-copy\",\n     .binding = \"Control+c\",\n     .comment = \"Copy to clipboard\"},\n    {.id = CLEAR_LINE,\n     .name = \"kb-clear-line\",\n     .binding = \"Control+w\",\n     .comment = \"Clear input line\"},\n    {.id = MOVE_FRONT,\n     .name = \"kb-move-front\",\n     .binding = \"Control+a\",\n     .comment = \"Beginning of line\"},\n    {.id = MOVE_END,\n     .name = \"kb-move-end\",\n     .binding = \"Control+e\",\n     .comment = \"End of line\"},\n    {.id = MOVE_WORD_BACK,\n     .name = \"kb-move-word-back\",\n     .binding = \"Alt+b,Control+Left\",\n     .comment = \"Move back one word\"},\n    {.id = MOVE_WORD_FORWARD,\n     .name = \"kb-move-word-forward\",\n     .binding = \"Alt+f,Control+Right\",\n     .comment = \"Move forward one word\"},\n    {.id = MOVE_CHAR_BACK,\n     .name = \"kb-move-char-back\",\n     .binding = \"Left,Control+b\",\n     .comment = \"Move back one char\"},\n    {.id = MOVE_CHAR_FORWARD,\n     .name = \"kb-move-char-forward\",\n     .binding = \"Right,Control+f\",\n     .comment = \"Move forward one char\"},\n    {.id = REMOVE_WORD_BACK,\n     .name = \"kb-remove-word-back\",\n     .binding = \"Control+Alt+h,Control+BackSpace\",\n     .comment = \"Delete previous word\"},\n    {.id = REMOVE_WORD_FORWARD,\n     .name = \"kb-remove-word-forward\",\n     .binding = \"Control+Alt+d\",\n     .comment = \"Delete next word\"},\n    {.id = REMOVE_CHAR_FORWARD,\n     .name = \"kb-remove-char-forward\",\n     .binding = \"Delete,Control+d\",\n     .comment = \"Delete next char\"},\n    {.id = REMOVE_CHAR_BACK,\n     .name = \"kb-remove-char-back\",\n     .binding = \"BackSpace,Shift+BackSpace,Control+h\",\n     .comment = \"Delete previous char\"},\n    {.id = REMOVE_TO_EOL,\n     .name = \"kb-remove-to-eol\",\n     .binding = \"Control+k\",\n     .comment = \"Delete till the end of line\"},\n    {.id = REMOVE_TO_SOL,\n     .name = \"kb-remove-to-sol\",\n     .binding = \"Control+u\",\n     .comment = \"Delete till the start of line\"},\n    {.id = TRANSPOSE_CHARS,\n     .name = \"kb-transpose-chars\",\n     .binding = \"Control+t\",\n     .comment = \"Transpose (swap) two chars before cursor\"},\n    {.id = ACCEPT_ENTRY,\n     .name = \"kb-accept-entry\",\n     .binding = \"Control+j,Control+m,Return,KP_Enter\",\n     .comment = \"Accept entry\"},\n    {.id = ACCEPT_CUSTOM,\n     .name = \"kb-accept-custom\",\n     .binding = \"Control+Return\",\n     .comment = \"Use entered text as command (in ssh/run modes)\"},\n    {.id = ACCEPT_CUSTOM_ALT,\n     .name = \"kb-accept-custom-alt\",\n     .binding = \"Control+Shift+Return\",\n     .comment = \"Use entered text as command (in ssh/run modes)\"},\n    {.id = ACCEPT_ALT,\n     .name = \"kb-accept-alt\",\n     .binding = \"Shift+Return\",\n     .comment = \"Use alternate accept command.\"},\n    {.id = DELETE_ENTRY,\n     .name = \"kb-delete-entry\",\n     .binding = \"Shift+Delete\",\n     .comment = \"Delete entry from history\"},\n    {.id = MODE_NEXT,\n     .name = \"kb-mode-next\",\n     .binding = \"Shift+Right,Control+Tab\",\n     .comment = \"Switch to the next mode.\"},\n    {.id = MODE_PREVIOUS,\n     .name = \"kb-mode-previous\",\n     .binding = \"Shift+Left,Control+ISO_Left_Tab\",\n     .comment = \"Switch to the previous mode.\"},\n    {.id = MODE_COMPLETE,\n     .name = \"kb-mode-complete\",\n     .binding = \"Control+l\",\n     .comment = \"Start completion for mode.\"},\n    {.id = ROW_LEFT,\n     .name = \"kb-row-left\",\n     .binding = \"Control+Page_Up\",\n     .comment = \"Go to the previous column\"},\n    {.id = ROW_RIGHT,\n     .name = \"kb-row-right\",\n     .binding = \"Control+Page_Down\",\n     .comment = \"Go to the next column\"},\n    {.id = ROW_UP,\n     .name = \"kb-row-up\",\n     .binding = \"Up,Control+p\",\n     .comment = \"Select previous entry\"},\n    {.id = ROW_DOWN,\n     .name = \"kb-row-down\",\n     .binding = \"Down,Control+n\",\n     .comment = \"Select next entry\"},\n    {.id = ROW_TAB,\n     .name = \"kb-row-tab\",\n     .binding = \"\",\n     .comment =\n         \"Go to next row, if one left, accept it, if no left next mode.\"},\n    {.id = ELEMENT_NEXT,\n     .name = \"kb-element-next\",\n     .binding = \"Tab\",\n     .comment = \"Go to next element (in logical order).\"},\n    {.id = ELEMENT_PREV,\n     .name = \"kb-element-prev\",\n     .binding = \"ISO_Left_Tab\",\n     .comment = \"Go to next previous element (in logical order).\"},\n    {.id = PAGE_PREV,\n     .name = \"kb-page-prev\",\n     .binding = \"Page_Up\",\n     .comment = \"Go to the previous page\"},\n    {.id = PAGE_NEXT,\n     .name = \"kb-page-next\",\n     .binding = \"Page_Down\",\n     .comment = \"Go to the next page\"},\n    {.id = ROW_FIRST,\n     .name = \"kb-row-first\",\n     .binding = \"Home,KP_Home\",\n     .comment = \"Go to the first entry\"},\n    {.id = ROW_LAST,\n     .name = \"kb-row-last\",\n     .binding = \"End,KP_End\",\n     .comment = \"Go to the last entry\"},\n    {.id = ROW_SELECT,\n     .name = \"kb-row-select\",\n     .binding = \"Control+space\",\n     .comment = \"Set selected item as input text\"},\n    {.id = SCREENSHOT,\n     .name = \"kb-screenshot\",\n     .binding = \"Alt+S\",\n     .comment = \"Take a screenshot of the rofi window\"},\n    {.id = CHANGE_ELLIPSIZE,\n     .name = \"kb-ellipsize\",\n     .binding = \"Alt+period\",\n     .comment = \"Toggle between ellipsize modes for displayed data\"},\n    {.id = TOGGLE_CASE_SENSITIVITY,\n     .name = \"kb-toggle-case-sensitivity\",\n     .binding = \"grave,dead_grave\",\n     .comment = \"Toggle case sensitivity\"},\n    {.id = TOGGLE_SORT,\n     .name = \"kb-toggle-sort\",\n     .binding = \"Alt+grave\",\n    .comment = \"Toggle sort\"},\n    {.id = CANCEL,\n     .name = \"kb-cancel\",\n     .binding = \"Escape,Control+g,Control+bracketleft,MouseSecondary\",\n     .comment = \"Quit rofi\"},\n    {.id = CUSTOM_1,\n     .name = \"kb-custom-1\",\n     .binding = \"Alt+1\",\n     .comment = \"Custom keybinding 1\"},\n    {.id = CUSTOM_2,\n     .name = \"kb-custom-2\",\n     .binding = \"Alt+2\",\n     .comment = \"Custom keybinding 2\"},\n    {.id = CUSTOM_3,\n     .name = \"kb-custom-3\",\n     .binding = \"Alt+3\",\n     .comment = \"Custom keybinding 3\"},\n    {.id = CUSTOM_4,\n     .name = \"kb-custom-4\",\n     .binding = \"Alt+4\",\n     .comment = \"Custom keybinding 4\"},\n    {.id = CUSTOM_5,\n     .name = \"kb-custom-5\",\n     .binding = \"Alt+5\",\n     .comment = \"Custom Keybinding 5\"},\n    {.id = CUSTOM_6,\n     .name = \"kb-custom-6\",\n     .binding = \"Alt+6\",\n     .comment = \"Custom keybinding 6\"},\n    {.id = CUSTOM_7,\n     .name = \"kb-custom-7\",\n     .binding = \"Alt+7\",\n     .comment = \"Custom Keybinding 7\"},\n    {.id = CUSTOM_8,\n     .name = \"kb-custom-8\",\n     .binding = \"Alt+8\",\n     .comment = \"Custom keybinding 8\"},\n    {.id = CUSTOM_9,\n     .name = \"kb-custom-9\",\n     .binding = \"Alt+9\",\n     .comment = \"Custom keybinding 9\"},\n    {.id = CUSTOM_10,\n     .name = \"kb-custom-10\",\n     .binding = \"Alt+0\",\n     .comment = \"Custom keybinding 10\"},\n    {.id = CUSTOM_11,\n     .name = \"kb-custom-11\",\n     .binding = \"Alt+exclam\",\n     .comment = \"Custom keybinding 11\"},\n    {.id = CUSTOM_12,\n     .name = \"kb-custom-12\",\n     .binding = \"Alt+at\",\n     .comment = \"Custom keybinding 12\"},\n    {.id = CUSTOM_13,\n     .name = \"kb-custom-13\",\n     .binding = \"Alt+numbersign\",\n     .comment = \"Custom keybinding 13\"},\n    {.id = CUSTOM_14,\n     .name = \"kb-custom-14\",\n     .binding = \"Alt+dollar\",\n     .comment = \"Custom keybinding 14\"},\n    {.id = CUSTOM_15,\n     .name = \"kb-custom-15\",\n     .binding = \"Alt+percent\",\n     .comment = \"Custom keybinding 15\"},\n    {.id = CUSTOM_16,\n     .name = \"kb-custom-16\",\n     .binding = \"Alt+dead_circumflex\",\n     .comment = \"Custom keybinding 16\"},\n    {.id = CUSTOM_17,\n     .name = \"kb-custom-17\",\n     .binding = \"Alt+ampersand\",\n     .comment = \"Custom keybinding 17\"},\n    {.id = CUSTOM_18,\n     .name = \"kb-custom-18\",\n     .binding = \"Alt+asterisk\",\n     .comment = \"Custom keybinding 18\"},\n    {.id = CUSTOM_19,\n     .name = \"kb-custom-19\",\n     .binding = \"Alt+parenleft\",\n     .comment = \"Custom Keybinding 19\"},\n    {.id = SELECT_ELEMENT_1,\n     .name = \"kb-select-1\",\n     .binding = \"Super+1\",\n     .comment = \"Select row 1\"},\n    {.id = SELECT_ELEMENT_2,\n     .name = \"kb-select-2\",\n     .binding = \"Super+2\",\n     .comment = \"Select row 2\"},\n    {.id = SELECT_ELEMENT_3,\n     .name = \"kb-select-3\",\n     .binding = \"Super+3\",\n     .comment = \"Select row 3\"},\n    {.id = SELECT_ELEMENT_4,\n     .name = \"kb-select-4\",\n     .binding = \"Super+4\",\n     .comment = \"Select row 4\"},\n    {.id = SELECT_ELEMENT_5,\n     .name = \"kb-select-5\",\n     .binding = \"Super+5\",\n     .comment = \"Select row 5\"},\n    {.id = SELECT_ELEMENT_6,\n     .name = \"kb-select-6\",\n     .binding = \"Super+6\",\n     .comment = \"Select row 6\"},\n    {.id = SELECT_ELEMENT_7,\n     .name = \"kb-select-7\",\n     .binding = \"Super+7\",\n     .comment = \"Select row 7\"},\n    {.id = SELECT_ELEMENT_8,\n     .name = \"kb-select-8\",\n     .binding = \"Super+8\",\n     .comment = \"Select row 8\"},\n    {.id = SELECT_ELEMENT_9,\n     .name = \"kb-select-9\",\n     .binding = \"Super+9\",\n     .comment = \"Select row 9\"},\n    {.id = SELECT_ELEMENT_10,\n     .name = \"kb-select-10\",\n     .binding = \"Super+0\",\n     .comment = \"Select row 10\"},\n    {.id = ENTRY_HISTORY_UP,\n     .name = \"kb-entry-history-up\",\n     .binding = \"Control+Up\",\n     .comment = \"Go up in the history of the entry box\"},\n    {.id = ENTRY_HISTORY_DOWN,\n     .name = \"kb-entry-history-down\",\n     .binding = \"Control+Down\",\n     .comment = \"Go down in the history of the entry box\"},\n    {.id = MATCHER_UP,\n     .name = \"kb-matcher-up\",\n     .binding = \"Super+equal\",\n     .comment = \"Switch to the previous matcher\"},\n    {.id = MATCHER_DOWN,\n     .name = \"kb-matcher-down\",\n     .binding = \"Super+minus\",\n     .comment = \"Switch to the next matcher\"},\n\n    /* Mouse-aware bindings */\n\n    {.id = SCROLL_LEFT,\n     .scope = SCOPE_MOUSE_LISTVIEW,\n     .name = \"ml-row-left\",\n     .binding = \"ScrollLeft\",\n     .comment = \"Go to the previous column\"},\n    {.id = SCROLL_RIGHT,\n     .scope = SCOPE_MOUSE_LISTVIEW,\n     .name = \"ml-row-right\",\n     .binding = \"ScrollRight\",\n     .comment = \"Go to the next column\"},\n    {.id = SCROLL_UP,\n     .scope = SCOPE_MOUSE_LISTVIEW,\n     .name = \"ml-row-up\",\n     .binding = \"ScrollUp\",\n     .comment = \"Select previous entry\"},\n    {.id = SCROLL_DOWN,\n     .scope = SCOPE_MOUSE_LISTVIEW,\n     .name = \"ml-row-down\",\n     .binding = \"ScrollDown\",\n     .comment = \"Select next entry\"},\n\n    {.id = SELECT_HOVERED_ENTRY,\n     .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT,\n     .name = \"me-select-entry\",\n     .binding = \"MousePrimary\",\n     .comment = \"Select hovered row\"},\n    {.id = ACCEPT_HOVERED_ENTRY,\n     .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT,\n     .name = \"me-accept-entry\",\n     .binding = \"MouseDPrimary\",\n     .comment = \"Accept hovered row\"},\n    {.id = ACCEPT_HOVERED_CUSTOM,\n     .scope = SCOPE_MOUSE_LISTVIEW_ELEMENT,\n     .name = \"me-accept-custom\",\n     .binding = \"Control+MouseDPrimary\",\n     .comment = \"Accept hovered row with custom action\"},\n};\n\n/** Default binding of mouse button to action. */\nstatic const gchar *mouse_default_bindings[] = {\n    [MOUSE_CLICK_DOWN] = \"MousePrimary\",\n    [MOUSE_CLICK_UP] = \"!MousePrimary\",\n    [MOUSE_DCLICK_DOWN] = \"MouseDPrimary\",\n    [MOUSE_DCLICK_UP] = \"!MouseDPrimary\",\n};\n\nvoid abe_list_all_bindings(gboolean is_term) {\n\n  int length = 0;\n  for (gsize i = 0; i < G_N_ELEMENTS(rofi_bindings); ++i) {\n    ActionBindingEntry *b = &rofi_bindings[i];\n    int sl = strlen(b->name);\n    length = MAX(length, sl);\n  }\n  for (gsize i = 0; i < G_N_ELEMENTS(rofi_bindings); ++i) {\n    ActionBindingEntry *b = &rofi_bindings[i];\n    if (is_term) {\n      printf(\"%s%*s%s - %s\\n\", color_bold, length, b->name, color_reset,\n             b->binding);\n    } else {\n      printf(\"%*s - %s\\n\", length, b->name, b->binding);\n    }\n  }\n}\n\nvoid setup_abe(void) {\n  for (gsize i = 0; i < G_N_ELEMENTS(rofi_bindings); ++i) {\n    ActionBindingEntry *b = &rofi_bindings[i];\n    b->binding = g_strdup(b->binding);\n    config_parser_add_option(xrm_String, b->name, (void **)&(b->binding),\n                             b->comment);\n  }\n}\n\nstatic gboolean binding_check_action(guint64 scope,\n                                     G_GNUC_UNUSED gpointer target,\n                                     gpointer user_data) {\n  return rofi_view_check_action(rofi_view_get_active(), scope,\n                                GPOINTER_TO_UINT(user_data))\n             ? NK_BINDINGS_BINDING_TRIGGERED\n             : NK_BINDINGS_BINDING_NOT_TRIGGERED;\n}\n\nstatic void binding_trigger_action(guint64 scope, G_GNUC_UNUSED gpointer target,\n                                   gpointer user_data) {\n  rofi_view_trigger_action(rofi_view_get_active(), scope,\n                           GPOINTER_TO_UINT(user_data));\n}\n\nguint key_binding_get_action_from_name(const char *name) {\n  for (gsize i = 0; i < G_N_ELEMENTS(rofi_bindings); ++i) {\n    ActionBindingEntry *b = &rofi_bindings[i];\n    if (g_strcmp0(b->name, name) == 0) {\n      return b->id;\n    }\n  }\n  return UINT32_MAX;\n}\n\ngboolean parse_keys_abe(NkBindings *bindings) {\n  GError *error = NULL;\n  GString *error_msg = g_string_new(\"\");\n  for (gsize i = 0; i < G_N_ELEMENTS(rofi_bindings); ++i) {\n    ActionBindingEntry *b = &rofi_bindings[i];\n    char *keystr = g_strdup(b->binding);\n    char *sp = NULL;\n\n    // Iter over bindings.\n    const char *const sep = \",\";\n    for (char *entry = strtok_r(keystr, sep, &sp); entry != NULL;\n         entry = strtok_r(NULL, sep, &sp)) {\n      if (!nk_bindings_add_binding(bindings, b->scope, entry,\n                                   binding_check_action, binding_trigger_action,\n                                   GUINT_TO_POINTER(b->id), NULL,\n                                   NK_BINDINGS_ADD_FLAG_NONE, &error)) {\n        if (error->code == NK_BINDINGS_ERROR_ALREADY_REGISTERED &&\n            error->domain == NK_BINDINGS_ERROR) {\n          char *str = g_markup_printf_escaped(\n              \"Failed to set binding <i>%s</i> for: <i>%s (%s)</i>:\\n\\t<span \"\n              \"size=\\\"smaller\\\" style=\\\"italic\\\">Binding `%s` is already \"\n              \"bound.\\n\"\n              \"\\tExecute <b>rofi -list-keybindings</b> to get the current list \"\n              \"of configured bindings.</span>\\n\",\n              b->binding, b->comment, b->name, entry);\n          g_string_append(error_msg, str);\n          g_free(str);\n        } else {\n          char *str = g_markup_printf_escaped(\n              \"Failed to set binding <i>%s</i> for: <i>%s (%s)</i>:\\n\\t<span \"\n              \"size=\\\"smaller\\\" style=\\\"italic\\\">%s</span>\\n\",\n              b->binding, b->comment, b->name, error->message);\n          g_string_append(error_msg, str);\n          g_free(str);\n        }\n        g_clear_error(&error);\n      }\n    }\n\n    g_free(keystr);\n  }\n  if (error_msg->len > 0) {\n    // rofi_view_error_dialog ( error_msg->str, TRUE );\n    rofi_add_error_message(error_msg);\n    //        g_string_free ( error_msg, TRUE );\n    return FALSE;\n  }\n\n  for (gsize i = SCOPE_MIN_FIXED; i <= SCOPE_MAX_FIXED; ++i) {\n    for (gsize j = 1; j < G_N_ELEMENTS(mouse_default_bindings); ++j) {\n      nk_bindings_add_binding(bindings, i, mouse_default_bindings[j],\n                              binding_check_action, binding_trigger_action,\n                              GSIZE_TO_POINTER(j), NULL,\n                              NK_BINDINGS_ADD_FLAG_NONE, NULL);\n    }\n  }\n\n  g_string_free(error_msg, TRUE);\n  return TRUE;\n}\n"
  },
  {
    "path": "source/mode.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"mode.h\"\n#include \"rofi.h\"\n#include \"xrmoptions.h\"\n#include <glib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"rofi-icon-fetcher.h\"\n// This one should only be in mode implementations.\n#include \"helper.h\"\n#include \"mode-private.h\"\n/**\n * @ingroup MODE\n * @{\n */\n\nint mode_init(Mode *mode) {\n  g_return_val_if_fail(mode != NULL, FALSE);\n  g_return_val_if_fail(mode->_init != NULL, FALSE);\n  if (mode->type == MODE_TYPE_UNSET) {\n    g_warning(\"Mode '%s' does not have a type set. Please update mode/plugin.\",\n              mode->name);\n  }\n  if ((mode->type & MODE_TYPE_COMPLETER) == MODE_TYPE_COMPLETER) {\n    if (mode->_completer_result == NULL) {\n      g_error(\n          \"Mode '%s' is incomplete and does not implement _completer_result.\",\n          mode->name);\n    }\n  }\n  // to make sure this is initialized correctly.\n  mode->fallback_icon_fetch_uid = 0;\n  mode->fallback_icon_not_found = FALSE;\n  return mode->_init(mode);\n}\n\nvoid mode_destroy(Mode *mode) {\n  g_assert(mode != NULL);\n  g_assert(mode->_destroy != NULL);\n  mode->_destroy(mode);\n}\n\nunsigned int mode_get_num_entries(const Mode *mode) {\n  g_assert(mode != NULL);\n  g_assert(mode->_get_num_entries != NULL);\n  return mode->_get_num_entries(mode);\n}\n\nchar *mode_get_display_value(const Mode *mode, unsigned int selected_line,\n                             int *state, GList **attribute_list,\n                             int get_entry) {\n  g_assert(mode != NULL);\n  g_assert(state != NULL);\n  g_assert(mode->_get_display_value != NULL);\n\n  return mode->_get_display_value(mode, selected_line, state, attribute_list,\n                                  get_entry);\n}\n\ncairo_surface_t *mode_get_icon(Mode *mode, unsigned int selected_line,\n                               unsigned int height) {\n  g_assert(mode != NULL);\n\n  if (mode->_get_icon != NULL) {\n    cairo_surface_t *icon = mode->_get_icon(mode, selected_line, height);\n    if (icon) {\n      return icon;\n    }\n  }\n\n  if (mode->fallback_icon_not_found == TRUE) {\n    return NULL;\n  }\n  if (mode->fallback_icon_fetch_uid > 0) {\n    cairo_surface_t *icon =\n        rofi_icon_fetcher_get(mode->fallback_icon_fetch_uid);\n    return icon;\n  }\n  ThemeWidget *wid = rofi_config_find_widget(mode->name, NULL, TRUE);\n  if (wid) {\n    /** Load user entires */\n    Property *p =\n        rofi_theme_find_property(wid, P_STRING, \"fallback-icon\", TRUE);\n    if (p != NULL && (p->type == P_STRING && p->value.s)) {\n      mode->fallback_icon_fetch_uid =\n          rofi_icon_fetcher_query(p->value.s, height);\n      return NULL;\n    }\n  }\n  mode->fallback_icon_not_found = TRUE;\n  return NULL;\n}\n\nchar *mode_get_completion(const Mode *mode, unsigned int selected_line) {\n  g_assert(mode != NULL);\n  if (mode->_get_completion != NULL) {\n    return mode->_get_completion(mode, selected_line);\n  }\n  int state;\n  g_assert(mode->_get_display_value != NULL);\n  return mode->_get_display_value(mode, selected_line, &state, NULL, TRUE);\n}\n\nModeMode mode_result(Mode *mode, int menu_retv, char **input,\n                     unsigned int selected_line) {\n  if (menu_retv & MENU_NEXT) {\n    return NEXT_DIALOG;\n  }\n  if (menu_retv & MENU_PREVIOUS) {\n    return PREVIOUS_DIALOG;\n  }\n  if (menu_retv & MENU_QUICK_SWITCH) {\n    return menu_retv & MENU_LOWER_MASK;\n  }\n\n  g_assert(mode != NULL);\n  g_assert(mode->_result != NULL);\n  g_assert(input != NULL);\n\n  return mode->_result(mode, menu_retv, input, selected_line);\n}\n\nint mode_token_match(const Mode *mode, rofi_int_matcher **tokens,\n                     unsigned int selected_line) {\n  g_assert(mode != NULL);\n  g_assert(mode->_token_match != NULL);\n  return mode->_token_match(mode, tokens, selected_line);\n}\n\nconst char *mode_get_name(const Mode *mode) {\n  g_assert(mode != NULL);\n  return mode->name;\n}\n\nint mode_get_abi_version(Mode *const mode) {\n  g_assert(mode != NULL);\n  return mode->abi_version;\n}\n\nvoid mode_free(Mode **mode) {\n  g_assert(mode != NULL);\n  g_assert((*mode) != NULL);\n  if ((*mode)->free != NULL) {\n    (*mode)->free(*mode);\n  }\n  (*mode) = NULL;\n}\n\nvoid *mode_get_private_data(const Mode *mode) {\n  g_assert(mode != NULL);\n  return mode->private_data;\n}\n\nvoid mode_set_private_data(Mode *mode, void *pd) {\n  g_assert(mode != NULL);\n  if (pd != NULL) {\n    g_assert(mode->private_data == NULL);\n  }\n  mode->private_data = pd;\n}\n\nconst char *mode_get_display_name(const Mode *mode) {\n  /** Find the widget */\n  ThemeWidget *wid = rofi_config_find_widget(mode->name, NULL, TRUE);\n  if (wid) {\n    /** Check string property */\n    Property *p = rofi_theme_find_property(wid, P_STRING, \"display-name\", TRUE);\n    if (p != NULL && p->type == P_STRING) {\n      return p->value.s;\n    }\n  }\n  if (mode->display_name != NULL) {\n    return mode->display_name;\n  }\n  return mode->name;\n}\n\nvoid mode_set_config(Mode *mode) {\n  snprintf(mode->cfg_name_key, 128, \"display-%s\", mode->name);\n  config_parser_add_option(xrm_String, mode->cfg_name_key,\n                           (void **)&(mode->display_name),\n                           \"The display name of this browser\");\n}\n\nchar *mode_preprocess_input(Mode *mode, const char *input) {\n  if (mode->_preprocess_input) {\n    return mode->_preprocess_input(mode, input);\n  }\n  return g_strdup(input);\n}\nchar *mode_get_message(const Mode *mode) {\n  if (mode->_get_message) {\n    return mode->_get_message(mode);\n  }\n  return NULL;\n}\n\nMode *mode_create(const Mode *mode) {\n  if (mode->_create) {\n    return mode->_create();\n  }\n  return NULL;\n}\n\nModeMode mode_completer_result(Mode *mode, int menu_retv, char **input,\n                               unsigned int selected_line, char **path) {\n  if ((mode->type & MODE_TYPE_COMPLETER) == 0) {\n    g_warning(\"Trying to call completer_result on non completion mode.\");\n    return 0;\n  }\n  if (mode->_completer_result) {\n    return mode->_completer_result(mode, menu_retv, input, selected_line, path);\n  }\n  return 0;\n}\n\ngboolean mode_is_completer(const Mode *mode) {\n  if (mode) {\n    if ((mode->type & MODE_TYPE_COMPLETER) == MODE_TYPE_COMPLETER) {\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n\nvoid mode_plugin_set_module(Mode *mode, GModule *mod){\n  mode->module = mod;\n}\nGModule *mode_plugin_get_module(Mode *mode){\n  return mode->module;\n}\n/**@}*/\n"
  },
  {
    "path": "source/modes/combi.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this dialog. */\n#define G_LOG_DOMAIN \"Modes.Combi\"\n\n#include \"helper.h\"\n#include \"settings.h\"\n#include <rofi.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"mode-private.h\"\n#include \"widgets/textbox.h\"\n#include <modes/modes.h>\n#include <pango/pango.h>\n#include <theme.h>\n\n/**\n * Combi Mode\n */\ntypedef struct {\n  Mode *mode;\n  gboolean disable;\n} CombiMode;\n\ntypedef struct {\n  // List of (combined) entries.\n  unsigned int cmd_list_length;\n  // List to validate where each switcher starts.\n  unsigned int *starts;\n  unsigned int *lengths;\n  // List of switchers to combine.\n  unsigned int num_switchers;\n  CombiMode *switchers;\n} CombiModePrivateData;\n\nstatic void combi_mode_parse_switchers(Mode *sw) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  char *savept = NULL;\n  // Make a copy, as strtok will modify it.\n  char *switcher_str = g_strdup(config.combi_modes);\n  const char *const sep = \",#\";\n  // Split token on ','. This modifies switcher_str.\n  for (char *token = strtok_r(switcher_str, sep, &savept); token != NULL;\n       token = strtok_r(NULL, sep, &savept)) {\n    /* Check against recursion. */\n    if (g_strcmp0(token, sw->name) == 0) {\n      g_warning(\"You cannot add '%s' to the list of combined modes.\", sw->name);\n      continue;\n    }\n    // Resize and add entry.\n    pd->switchers = (CombiMode *)g_realloc(\n        pd->switchers, sizeof(CombiMode) * (pd->num_switchers + 1));\n\n    Mode *mode = rofi_collect_modes_search(token);\n    if (mode != NULL) {\n      pd->switchers[pd->num_switchers].disable = FALSE;\n      pd->switchers[pd->num_switchers++].mode = mode;\n      continue;\n    }\n    // If not build in, use custom switchers.\n    mode = script_mode_parse_setup(token);\n    if (mode != NULL) {\n      pd->switchers[pd->num_switchers].disable = FALSE;\n      pd->switchers[pd->num_switchers++].mode = mode;\n      continue;\n    }\n    // Report error, don't continue.\n    g_warning(\"Invalid script switcher: %s\", token);\n    token = NULL;\n  }\n  // Free string that was modified by strtok_r\n  g_free(switcher_str);\n}\nstatic unsigned int combi_mode_get_num_entries(const Mode *sw) {\n  const CombiModePrivateData *pd =\n      (const CombiModePrivateData *)mode_get_private_data(sw);\n  unsigned int length = 0;\n  for (unsigned int i = 0; i < pd->num_switchers; i++) {\n    unsigned int entries = mode_get_num_entries(pd->switchers[i].mode);\n    pd->starts[i] = length;\n    pd->lengths[i] = entries;\n    length += entries;\n  }\n  return length;\n}\n\nstatic int combi_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n    CombiModePrivateData *pd = g_malloc0(sizeof(*pd));\n    mode_set_private_data(sw, (void *)pd);\n    combi_mode_parse_switchers(sw);\n    pd->starts = g_malloc0(sizeof(int) * pd->num_switchers);\n    pd->lengths = g_malloc0(sizeof(int) * pd->num_switchers);\n    for (unsigned int i = 0; i < pd->num_switchers; i++) {\n      if (!mode_init(pd->switchers[i].mode)) {\n        return FALSE;\n      }\n    }\n    if (pd->cmd_list_length == 0) {\n      pd->cmd_list_length = combi_mode_get_num_entries(sw);\n    }\n  }\n  return TRUE;\n}\nstatic void combi_mode_destroy(Mode *sw) {\n  CombiModePrivateData *pd = (CombiModePrivateData *)mode_get_private_data(sw);\n  if (pd != NULL) {\n    g_free(pd->starts);\n    g_free(pd->lengths);\n    // Cleanup switchers.\n    for (unsigned int i = 0; i < pd->num_switchers; i++) {\n      mode_destroy(pd->switchers[i].mode);\n    }\n    g_free(pd->switchers);\n    g_free(pd);\n    mode_set_private_data(sw, NULL);\n  }\n}\nstatic ModeMode combi_mode_result(Mode *sw, int mretv, char **input,\n                                  unsigned int selected_line) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n\n  if (input[0][0] == '!') {\n    int switcher = -1;\n    // Implement strchrnul behaviour.\n    char *eob = g_utf8_strchr(input[0], -1, ' ');\n    if (eob == NULL) {\n      eob = &(input[0][strlen(input[0])]);\n    }\n    ssize_t bang_len = g_utf8_pointer_to_offset(input[0], eob) - 1;\n    if (bang_len > 0) {\n      for (unsigned i = 0; i < pd->num_switchers; i++) {\n        const char *mode_name = mode_get_name(pd->switchers[i].mode);\n        size_t mode_name_len = g_utf8_strlen(mode_name, -1);\n        if ((size_t)bang_len <= mode_name_len &&\n            utf8_strncmp(&input[0][1], mode_name, bang_len) == 0) {\n          switcher = i;\n          break;\n        }\n      }\n    }\n    if (switcher >= 0) {\n      if (eob[0] == ' ') {\n        char *n = g_strdup(eob + 1);\n        ModeMode retv = mode_result(pd->switchers[switcher].mode, mretv, &n,\n                                    selected_line - pd->starts[switcher]);\n        g_free(n);\n        return retv;\n      } else if (eob[0] == '\\0') {\n        char *str = NULL;\n        ModeMode retv = mode_result(pd->switchers[switcher].mode, mretv, &str,\n                                    selected_line - pd->starts[switcher]);\n        g_free(str);\n        return retv;\n      }\n      return MODE_EXIT;\n    }\n  } else if ((mretv & MENU_COMPLETE)) {\n    return RELOAD_DIALOG;\n  }\n\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    if (selected_line >= pd->starts[i] &&\n        selected_line < (pd->starts[i] + pd->lengths[i])) {\n      return mode_result(pd->switchers[i].mode, mretv, input,\n                         selected_line - pd->starts[i]);\n    }\n  }\n  if ((mretv & MENU_CUSTOM_INPUT)) {\n    return mode_result(pd->switchers[0].mode, mretv, input, selected_line);\n  }\n  return MODE_EXIT;\n}\nstatic int combi_mode_match(const Mode *sw, rofi_int_matcher **tokens,\n                            unsigned int index) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    if (pd->switchers[i].disable) {\n      continue;\n    }\n    if (index >= pd->starts[i] && index < (pd->starts[i] + pd->lengths[i])) {\n      return mode_token_match(pd->switchers[i].mode, tokens,\n                              index - pd->starts[i]);\n    }\n  }\n  return 0;\n}\nstatic char *combi_mgrv(const Mode *sw, unsigned int selected_line, int *state,\n                        GList **attr_list, int get_entry) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  if (!get_entry) {\n    for (unsigned i = 0; i < pd->num_switchers; i++) {\n      if (selected_line >= pd->starts[i] &&\n          selected_line < (pd->starts[i] + pd->lengths[i])) {\n        mode_get_display_value(pd->switchers[i].mode,\n                               selected_line - pd->starts[i], state, attr_list,\n                               FALSE);\n        return NULL;\n      }\n    }\n    return NULL;\n  }\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    if (selected_line >= pd->starts[i] &&\n        selected_line < (pd->starts[i] + pd->lengths[i])) {\n      char *retv;\n      char *str = retv = mode_get_display_value(pd->switchers[i].mode,\n                                                selected_line - pd->starts[i],\n                                                state, attr_list, TRUE);\n      const char *dname = mode_get_display_name(pd->switchers[i].mode);\n\n      if (!config.combi_hide_mode_prefix) {\n        if (!(*state & MARKUP)) {\n          char *tmp = str;\n          str = g_markup_escape_text(tmp, -1);\n          g_free(tmp);\n          *state |= MARKUP;\n        }\n\n        retv = helper_string_replace_if_exists(config.combi_display_format,\n                                               \"{mode}\", dname, \"{text}\", str,\n                                               (char *)0);\n        g_free(str);\n\n        if (attr_list != NULL) {\n          ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n          Property *p = rofi_theme_find_property(\n              wid, P_COLOR, pd->switchers[i].mode->name, TRUE);\n          if (p != NULL) {\n            PangoAttribute *pa = pango_attr_foreground_new(\n                p->value.color.red * 65535, p->value.color.green * 65535,\n                p->value.color.blue * 65535);\n            pa->start_index = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;\n            pa->end_index = strlen(dname);\n            *attr_list = g_list_append(*attr_list, pa);\n          }\n        }\n      }\n      return retv;\n    }\n  }\n\n  return NULL;\n}\nstatic char *combi_get_completion(const Mode *sw, unsigned int index) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    if (index >= pd->starts[i] && index < (pd->starts[i] + pd->lengths[i])) {\n      char *comp =\n          mode_get_completion(pd->switchers[i].mode, index - pd->starts[i]);\n      char *mcomp =\n          g_strdup_printf(\"!%s %s\", mode_get_name(pd->switchers[i].mode), comp);\n      g_free(comp);\n      return mcomp;\n    }\n  }\n  // Should never get here.\n  g_assert_not_reached();\n  return NULL;\n}\n\nstatic cairo_surface_t *combi_get_icon(const Mode *sw, unsigned int index,\n                                       unsigned int height) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    if (index >= pd->starts[i] && index < (pd->starts[i] + pd->lengths[i])) {\n      cairo_surface_t *icon =\n          mode_get_icon(pd->switchers[i].mode, index - pd->starts[i], height);\n      return icon;\n    }\n  }\n  return NULL;\n}\n\nstatic char *combi_preprocess_input(Mode *sw, const char *input) {\n  CombiModePrivateData *pd = mode_get_private_data(sw);\n  for (unsigned i = 0; i < pd->num_switchers; i++) {\n    pd->switchers[i].disable = FALSE;\n  }\n  if (input != NULL && input[0] == '!') {\n    // Implement strchrnul behaviour.\n    const char *eob = g_utf8_strchr(input, -1, ' ');\n    if (eob == NULL) {\n      // Set it to end.\n      eob = &(input[strlen(input)]);\n    }\n    ssize_t bang_len = g_utf8_pointer_to_offset(input, eob) - 1;\n    if (bang_len > 0) {\n      for (unsigned i = 0; i < pd->num_switchers; i++) {\n        const char *mode_name = mode_get_name(pd->switchers[i].mode);\n        size_t mode_name_len = g_utf8_strlen(mode_name, -1);\n        if (!((size_t)bang_len <= mode_name_len &&\n              utf8_strncmp(&input[1], mode_name, bang_len) == 0)) {\n          // No match.\n          pd->switchers[i].disable = TRUE;\n        }\n      }\n      if (eob[0] == '\\0' || eob[1] == '\\0') {\n        return NULL;\n      }\n      return g_strdup(eob + 1);\n    }\n  }\n  return g_strdup(input);\n}\n\nMode combi_mode = {.name = \"combi\",\n                   .cfg_name_key = \"display-combi\",\n                   ._init = combi_mode_init,\n                   ._get_num_entries = combi_mode_get_num_entries,\n                   ._result = combi_mode_result,\n                   ._destroy = combi_mode_destroy,\n                   ._token_match = combi_mode_match,\n                   ._get_completion = combi_get_completion,\n                   ._get_display_value = combi_mgrv,\n                   ._get_icon = combi_get_icon,\n                   ._preprocess_input = combi_preprocess_input,\n                   .private_data = NULL,\n                   .free = NULL,\n                   .type = MODE_TYPE_SWITCHER};\n"
  },
  {
    "path": "source/modes/dmenu.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this dialog. */\n#define G_LOG_DOMAIN \"Modes.DMenu\"\n#include \"config.h\"\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"modes/dmenu.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"view.h\"\n#include \"widgets/textbox.h\"\n#include \"xrmoptions.h\"\n#include <ctype.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <gio/gio.h>\n#include <gio/gunixinputstream.h>\n#include <glib-unix.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"modes/dmenuscriptshared.h\"\n\nstatic int dmenu_mode_init(Mode *sw);\nstatic int dmenu_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                             unsigned int index);\nstatic cairo_surface_t *\ndmenu_get_icon(const Mode *sw, unsigned int selected_line, unsigned int height);\nstatic char *dmenu_get_message(const Mode *sw);\n\nstatic inline unsigned int bitget(uint32_t const *const array,\n                                  unsigned int index) {\n  uint32_t bit = index % 32;\n  uint32_t val = array[index / 32];\n  return (val >> bit) & 1;\n}\n\nstatic inline void bittoggle(uint32_t *const array, unsigned int index) {\n  uint32_t bit = index % 32;\n  uint32_t *v = &array[index / 32];\n  *v ^= 1 << bit;\n}\n\ntypedef struct {\n  /** Settings */\n  // Separator.\n  char separator;\n\n  unsigned int selected_line;\n  char *message;\n  char *format;\n  struct rofi_range_pair *urgent_list;\n  unsigned int num_urgent_list;\n  struct rofi_range_pair *active_list;\n  unsigned int num_active_list;\n  uint32_t *selected_list;\n  unsigned int num_selected_list;\n  unsigned int do_markup;\n  // List with entries.\n  DmenuScriptEntry *cmd_list;\n  unsigned int cmd_list_real_length;\n  unsigned int cmd_list_length;\n  unsigned int only_selected;\n  unsigned int selected_count;\n\n  gchar **columns;\n  gchar *column_separator;\n  gboolean multi_select;\n\n  GThread *reading_thread;\n  GAsyncQueue *async_queue;\n  gboolean async;\n  FILE *fd_file;\n  int fd;\n  int pipefd[2];\n  int pipefd2[2];\n  guint wake_source;\n  gboolean loading;\n\n  char *ballot_selected;\n  char *ballot_unselected;\n} DmenuModePrivateData;\n\n/** Maximum number of lines rofi parses async before it pushes it to the main\n * thread. */\n#define BLOCK_LINES_SIZE 2048\ntypedef struct {\n  unsigned int length;\n  DmenuScriptEntry values[BLOCK_LINES_SIZE];\n  DmenuModePrivateData *pd;\n} Block;\n\nstatic void read_add_block(DmenuModePrivateData *pd, Block **block, char *data,\n                           gsize len) {\n\n  if ((*block) == NULL) {\n    (*block) = g_malloc0(sizeof(Block));\n    (*block)->pd = pd;\n    (*block)->length = 0;\n  }\n  gsize data_len = len;\n  // Init.\n  (*block)->values[(*block)->length].icon_fetch_uid = 0;\n  (*block)->values[(*block)->length].icon_fetch_size = 0;\n  (*block)->values[(*block)->length].icon_fetch_scale = 0;\n  (*block)->values[(*block)->length].icon_fallback_index = 0;\n  (*block)->values[(*block)->length].icon_name = NULL;\n  (*block)->values[(*block)->length].meta = NULL;\n  (*block)->values[(*block)->length].info = NULL;\n  (*block)->values[(*block)->length].nonselectable = FALSE;\n  (*block)->values[(*block)->length].permanent = FALSE;\n  char *end = data;\n  while (end < data + len && *end != '\\0') {\n    end++;\n  }\n  if (end != data + len) {\n    data_len = end - data;\n    dmenuscript_parse_entry_extras(NULL, &((*block)->values[(*block)->length]),\n                                   end + 1, len - data_len);\n  }\n  char *utfstr = rofi_force_utf8(data, data_len);\n  (*block)->values[(*block)->length].entry = utfstr;\n  (*block)->values[(*block)->length + 1].entry = NULL;\n\n  (*block)->length++;\n}\n\nstatic void read_add(DmenuModePrivateData *pd, char *data, gsize len) {\n  gsize data_len = len;\n  if ((pd->cmd_list_length + 2) > pd->cmd_list_real_length) {\n    pd->cmd_list_real_length = MAX(pd->cmd_list_real_length * 2, 512);\n    pd->cmd_list = g_realloc(pd->cmd_list, (pd->cmd_list_real_length) *\n                                               sizeof(DmenuScriptEntry));\n  }\n  // Init.\n  pd->cmd_list[pd->cmd_list_length].icon_fetch_uid = 0;\n  pd->cmd_list[pd->cmd_list_length].icon_fetch_size = 0;\n  pd->cmd_list[pd->cmd_list_length].icon_fetch_scale = 0;\n  pd->cmd_list[pd->cmd_list_length].icon_fallback_index = 0;\n  pd->cmd_list[pd->cmd_list_length].icon_name = NULL;\n  pd->cmd_list[pd->cmd_list_length].display = NULL;\n  pd->cmd_list[pd->cmd_list_length].meta = NULL;\n  pd->cmd_list[pd->cmd_list_length].info = NULL;\n  pd->cmd_list[pd->cmd_list_length].active = FALSE;\n  pd->cmd_list[pd->cmd_list_length].urgent = FALSE;\n  pd->cmd_list[pd->cmd_list_length].nonselectable = FALSE;\n  char *end = data;\n  while (end < data + len && *end != '\\0') {\n    end++;\n  }\n  if (end != data + len) {\n    data_len = end - data;\n    dmenuscript_parse_entry_extras(NULL, &(pd->cmd_list[pd->cmd_list_length]),\n                                   end + 1, len - data_len);\n  }\n  char *utfstr = rofi_force_utf8(data, data_len);\n  pd->cmd_list[pd->cmd_list_length].entry = utfstr;\n  pd->cmd_list[pd->cmd_list_length + 1].entry = NULL;\n\n  pd->cmd_list_length++;\n}\n\n/**\n * This method is called from a  GSource that responds to READ available event\n * on the file descriptor of the IPC pipe with the reading thread.\n * This method runs in the same thread as the UI and updates the dmenu mode\n * internal administratinos with new items.\n *\n * The data is copied not via the pipe, but via the Async Queue.\n * A maximal BLOCK_LINES_SIZE items are added with one block.\n */\nstatic gboolean dmenu_async_read_proc(gint fd, GIOCondition condition,\n                                      gpointer user_data) {\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)user_data;\n  char command;\n  // Only interrested in read events.\n  if ((condition & G_IO_IN) != G_IO_IN) {\n    return G_SOURCE_CONTINUE;\n  }\n  // Read the entry from the pipe that was used to signal this action.\n  if (read(fd, &command, 1) == 1) {\n    if (command == 'r') {\n      Block *block = NULL;\n      gboolean changed = FALSE;\n      // Empty out the AsyncQueue (that is thread safe) from all blocks pushed\n      // into it.\n      while ((block = g_async_queue_try_pop(pd->async_queue)) != NULL) {\n\n        if (pd->cmd_list_real_length < (pd->cmd_list_length + block->length)) {\n          pd->cmd_list_real_length = MAX(pd->cmd_list_real_length * 2, 4096);\n          pd->cmd_list = g_realloc(pd->cmd_list, sizeof(DmenuScriptEntry) *\n                                                     pd->cmd_list_real_length);\n        }\n        memcpy(&(pd->cmd_list[pd->cmd_list_length]), &(block->values[0]),\n               sizeof(DmenuScriptEntry) * block->length);\n        pd->cmd_list_length += block->length;\n        g_free(block);\n        changed = TRUE;\n      }\n      if (changed) {\n        rofi_view_reload();\n      }\n    } else if (command == 'q') {\n      if (pd->loading) {\n        rofi_view_set_overlay(rofi_view_get_active(), NULL);\n      }\n    }\n  }\n  return G_SOURCE_CONTINUE;\n}\n\nstatic void read_input_sync(DmenuModePrivateData *pd, unsigned int pre_read) {\n  ssize_t nread = 0;\n  size_t len = 0;\n  char *line = NULL;\n  while (pre_read > 0 &&\n         (nread = getdelim(&line, &len, pd->separator, pd->fd_file)) != -1) {\n    if (line[nread - 1] == pd->separator) {\n      nread--;\n      line[nread] = '\\0';\n    }\n    read_add(pd, line, nread);\n    pre_read--;\n  }\n  free(line);\n  return;\n}\nstatic gpointer read_input_thread(gpointer userdata) {\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)userdata;\n  ssize_t nread = 0;\n  ssize_t len = 0;\n  char *line = NULL;\n  Block *block = NULL;\n\n  GTimer *tim = g_timer_new();\n  int fd = pd->fd;\n  while (1) {\n    // Wait for input from the input or from the main thread.\n    fd_set rfds;\n    // We wait for 0.25 seconds, before we flush what we have.\n    struct timeval tv = {.tv_sec = 0, .tv_usec = 250000};\n\n    FD_ZERO(&rfds);\n    FD_SET(fd, &rfds);\n    FD_SET(pd->pipefd[0], &rfds);\n\n    int retval = select(MAX(fd, pd->pipefd[0]) + 1, &rfds, NULL, NULL, &tv);\n    if (retval == -1) {\n      g_warning(\"select failed, giving up.\");\n      break;\n    } else if (retval) {\n      // We get input from the UI thread, this is always an abort.\n      if (FD_ISSET(pd->pipefd[0], &rfds)) {\n        break;\n      }\n      //  Input data is available.\n      if (FD_ISSET(fd, &rfds)) {\n        ssize_t readbytes = 0;\n        if ((nread + 1024) > len) {\n          line = g_realloc(line, (len + 2048));\n          len = len + 2048;\n        }\n        readbytes = read(fd, &line[nread], 1023);\n        if (readbytes > 0) {\n          nread += readbytes;\n          line[nread] = '\\0';\n          ssize_t i = 0;\n          while (i < nread) {\n            if (line[i] == pd->separator) {\n              line[i] = '\\0';\n              read_add_block(pd, &block, line, i);\n              memmove(&line[0], &line[i + 1], nread - (i + 1));\n              nread -= (i + 1);\n              i = 0;\n              if (block) {\n                double elapsed = g_timer_elapsed(tim, NULL);\n                if (elapsed >= 0.1 || block->length == BLOCK_LINES_SIZE) {\n                  g_timer_start(tim);\n                  g_async_queue_push(pd->async_queue, block);\n                  block = NULL;\n                  write(pd->pipefd2[1], \"r\", 1);\n                }\n              }\n            } else {\n              i++;\n            }\n          }\n        } else {\n          // remainder in buffer, then quit.\n          if (nread > 0) {\n            line[nread] = '\\0';\n            read_add_block(pd, &block, line, nread);\n          }\n          if (block) {\n            g_timer_start(tim);\n            g_async_queue_push(pd->async_queue, block);\n            block = NULL;\n            write(pd->pipefd2[1], \"r\", 1);\n          }\n          break;\n        }\n      }\n    } else {\n      // Timeout, pushout remainder data.\n      if (nread > 0) {\n        line[nread] = '\\0';\n        read_add_block(pd, &block, line, nread);\n        nread = 0;\n      }\n      if (block) {\n        g_timer_start(tim);\n        g_async_queue_push(pd->async_queue, block);\n        block = NULL;\n        write(pd->pipefd2[1], \"r\", 1);\n      }\n    }\n  }\n  g_timer_destroy(tim);\n  free(line);\n  write(pd->pipefd2[1], \"q\", 1);\n  return NULL;\n}\n\nstatic unsigned int dmenu_mode_get_num_entries(const Mode *sw) {\n  const DmenuModePrivateData *rmpd =\n      (const DmenuModePrivateData *)mode_get_private_data(sw);\n  unsigned int retv = rmpd->cmd_list_length;\n  return retv;\n}\n\nstatic gchar *dmenu_format_output_string(const DmenuModePrivateData *pd,\n                                         const char *input,\n                                         const unsigned int index,\n                                         gboolean multi_select) {\n  if (pd->columns == NULL) {\n    if (multi_select) {\n      if (index < pd->num_selected_list && bitget(pd->selected_list, index) == TRUE) {\n        return g_strdup_printf(\"%s%s\", pd->ballot_selected, input);\n      } else {\n        return g_strdup_printf(\"%s%s\", pd->ballot_unselected, input);\n      }\n    }\n    return g_strdup(input);\n  }\n  char *retv = NULL;\n  char **splitted =\n      g_regex_split_simple(pd->column_separator, input, G_REGEX_CASELESS, 00);\n  uint32_t ns = 0;\n  for (; splitted && splitted[ns]; ns++) {\n    ;\n  }\n  GString *str_retv = g_string_new(\"\");\n\n  if (multi_select) {\n    if (index < pd->num_selected_list && bitget(pd->selected_list, index) == TRUE) {\n      g_string_append(str_retv, pd->ballot_selected);\n    } else {\n      g_string_append(str_retv, pd->ballot_unselected);\n    }\n  }\n  for (uint32_t i = 0; pd->columns && pd->columns[i]; i++) {\n    unsigned int col_index =\n        (unsigned int)g_ascii_strtoull(pd->columns[i], NULL, 10);\n    if (col_index <= ns && col_index > 0) {\n      if (i == 0) {\n        g_string_append(str_retv, splitted[col_index - 1]);\n      } else {\n        g_string_append_c(str_retv, '\\t');\n        g_string_append(str_retv, splitted[col_index - 1]);\n      }\n    }\n  }\n  g_strfreev(splitted);\n  retv = str_retv->str;\n  g_string_free(str_retv, FALSE);\n  return retv;\n}\n\nstatic inline unsigned int get_index(unsigned int length, int index) {\n  if (index >= 0) {\n    return index;\n  }\n  if (((unsigned int)-index) <= length) {\n    return length + index;\n  }\n  // Out of range.\n  return UINT_MAX;\n}\n\nstatic char *dmenu_get_completion_data(const Mode *data, unsigned int index) {\n  Mode *sw = (Mode *)data;\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n  DmenuScriptEntry *retv = (DmenuScriptEntry *)pd->cmd_list;\n  if (retv[index].display) {\n    return dmenu_format_output_string(pd, retv[index].display, index, FALSE);\n  } else {\n    return dmenu_format_output_string(pd, retv[index].entry, index, FALSE);\n  }\n}\n\nstatic char *get_display_data(const Mode *data, unsigned int index, int *state,\n                              G_GNUC_UNUSED GList **list, int get_entry) {\n  Mode *sw = (Mode *)data;\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n  DmenuScriptEntry *retv = (DmenuScriptEntry *)pd->cmd_list;\n  for (unsigned int i = 0; i < pd->num_active_list; i++) {\n    unsigned int start =\n        get_index(pd->cmd_list_length, pd->active_list[i].start);\n    unsigned int stop = get_index(pd->cmd_list_length, pd->active_list[i].stop);\n    if (index >= start && index <= stop) {\n      *state |= ACTIVE;\n    }\n  }\n  for (unsigned int i = 0; i < pd->num_urgent_list; i++) {\n    unsigned int start =\n        get_index(pd->cmd_list_length, pd->urgent_list[i].start);\n    unsigned int stop = get_index(pd->cmd_list_length, pd->urgent_list[i].stop);\n    if (index >= start && index <= stop) {\n      *state |= URGENT;\n    }\n  }\n  if (index < pd->num_selected_list && bitget(pd->selected_list, index) == TRUE) {\n    *state |= SELECTED;\n  }\n  if (pd->do_markup) {\n    *state |= MARKUP;\n  }\n  if (pd->cmd_list[index].urgent) {\n    *state |= URGENT;\n  }\n  if (pd->cmd_list[index].active) {\n    *state |= ACTIVE;\n  }\n  char *my_retv = NULL;\n  if (retv[index].display) {\n    my_retv = (get_entry ? dmenu_format_output_string(pd, retv[index].display,\n                                                      index, pd->multi_select)\n                         : NULL);\n  } else {\n    my_retv = (get_entry ? dmenu_format_output_string(pd, retv[index].entry,\n                                                      index, pd->multi_select)\n                         : NULL);\n  }\n  return my_retv;\n}\n\nstatic void dmenu_mode_free(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n    return;\n  }\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n  if (pd != NULL) {\n\n    for (size_t i = 0; i < pd->cmd_list_length; i++) {\n      if (pd->cmd_list[i].entry) {\n        g_free(pd->cmd_list[i].entry);\n        g_strfreev(pd->cmd_list[i].icon_name);\n        g_free(pd->cmd_list[i].display);\n        g_free(pd->cmd_list[i].meta);\n        g_free(pd->cmd_list[i].info);\n      }\n    }\n    g_free(pd->cmd_list);\n    g_free(pd->urgent_list);\n    g_free(pd->active_list);\n    g_free(pd->selected_list);\n\n    g_free(pd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\n#include \"mode-private.h\"\n/** dmenu Mode object. */\nMode dmenu_mode = {.name = \"dmenu\",\n                   .cfg_name_key = \"display-combi\",\n                   ._init = dmenu_mode_init,\n                   ._get_num_entries = dmenu_mode_get_num_entries,\n                   ._result = NULL,\n                   ._destroy = dmenu_mode_free,\n                   ._token_match = dmenu_token_match,\n                   ._get_display_value = get_display_data,\n                   ._get_icon = dmenu_get_icon,\n                   ._get_completion = dmenu_get_completion_data,\n                   ._preprocess_input = NULL,\n                   ._get_message = dmenu_get_message,\n                   .private_data = NULL,\n                   .free = NULL,\n                   .display_name = \"dmenu\",\n                   .type = MODE_TYPE_DMENU};\n\nstatic int dmenu_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) != NULL) {\n    return TRUE;\n  }\n  mode_set_private_data(sw, g_malloc0(sizeof(DmenuModePrivateData)));\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n\n  pd->async = TRUE;\n  pd->multi_select = FALSE;\n\n  // For now these only work in sync mode.\n  if (find_arg(\"-sync\") >= 0 || find_arg(\"-dump\") >= 0 ||\n      find_arg(\"-select\") >= 0 || find_arg(\"-no-custom\") >= 0 ||\n      find_arg(\"-only-match\") >= 0 || config.auto_select ||\n      find_arg(\"-selected-row\") >= 0) {\n    pd->async = FALSE;\n  }\n  if (find_arg(\"-multi-select\") >= 0) {\n    pd->multi_select = TRUE;\n  }\n\n  pd->separator = '\\n';\n  pd->selected_line = UINT32_MAX;\n\n  find_arg_str(\"-mesg\", &(pd->message));\n\n  // Input data separator.\n  find_arg_char(\"-sep\", &(pd->separator));\n\n  find_arg_uint(\"-selected-row\", &(pd->selected_line));\n  // By default we print the unescaped line back.\n  pd->format = \"s\";\n\n  // Allow user to override the output format.\n  find_arg_str(\"-format\", &(pd->format));\n  // Urgent.\n  char *str = NULL;\n  find_arg_str(\"-u\", &str);\n  if (str != NULL) {\n    parse_ranges(str, &(pd->urgent_list), &(pd->num_urgent_list));\n  }\n  // Active\n  str = NULL;\n  find_arg_str(\"-a\", &str);\n  if (str != NULL) {\n    parse_ranges(str, &(pd->active_list), &(pd->num_active_list));\n  }\n\n  // DMENU COMPATIBILITY\n  unsigned int lines = DEFAULT_MENU_LINES;\n  find_arg_uint(\"-l\", &(lines));\n  if (lines != DEFAULT_MENU_LINES) {\n    Property *p = rofi_theme_property_create(P_INTEGER);\n    p->name = g_strdup(\"lines\");\n    p->value.i = lines;\n    ThemeWidget *wid = rofi_theme_find_or_create_name(rofi_theme, \"listview\");\n    GHashTable *table =\n        g_hash_table_new_full(g_str_hash, g_str_equal, NULL,\n                              (GDestroyNotify)rofi_theme_property_free);\n\n    g_hash_table_replace(table, p->name, p);\n    rofi_theme_widget_add_properties(wid, table);\n    g_hash_table_destroy(table);\n  }\n\n  str = NULL;\n  find_arg_str(\"-window-title\", &str);\n  if (str) {\n    dmenu_mode.display_name = str;\n  }\n\n  /**\n   * Dmenu compatibility.\n   * `-b` put on bottom.\n   */\n  if (find_arg(\"-b\") >= 0) {\n    config.location = 6;\n  }\n  /* -i case insensitive */\n  config.case_sensitive = TRUE;\n  if (find_arg(\"-i\") >= 0) {\n    config.case_sensitive = FALSE;\n  }\n  if (pd->async) {\n    pd->fd = STDIN_FILENO;\n    if (find_arg_str(\"-input\", &str)) {\n      char *estr = rofi_expand_path(str);\n      pd->fd = open(str, O_RDONLY | O_NONBLOCK | O_CLOEXEC);\n      if (pd->fd == -1) {\n        char *msg = g_markup_printf_escaped(\n            \"Failed to open file: <b>%s</b>:\\n\\t<i>%s</i>\", estr,\n            g_strerror(errno));\n        rofi_view_error_dialog(msg, TRUE);\n        g_free(msg);\n        g_free(estr);\n        return TRUE;\n      }\n      g_free(estr);\n    }\n\n    if (pipe(pd->pipefd) == -1) {\n      g_error(\"Failed to create pipe\");\n    }\n    if (pipe(pd->pipefd2) == -1) {\n      g_error(\"Failed to create pipe\");\n    }\n    pd->wake_source =\n        g_unix_fd_add(pd->pipefd2[0], G_IO_IN, dmenu_async_read_proc, pd);\n    // Create the message passing queue to the UI thread.\n    pd->async_queue = g_async_queue_new();\n    pd->reading_thread =\n        g_thread_new(\"dmenu-read\", (GThreadFunc)read_input_thread, pd);\n    pd->loading = TRUE;\n  } else {\n    pd->fd_file = stdin;\n    str = NULL;\n    if (find_arg_str(\"-input\", &str)) {\n      char *estr = rofi_expand_path(str);\n      pd->fd_file = fopen(str, \"r\");\n      if (pd->fd_file == NULL) {\n        char *msg = g_markup_printf_escaped(\n            \"Failed to open file: <b>%s</b>:\\n\\t<i>%s</i>\", estr,\n            g_strerror(errno));\n        rofi_view_error_dialog(msg, TRUE);\n        g_free(msg);\n        g_free(estr);\n        return TRUE;\n      }\n      g_free(estr);\n    }\n\n    read_input_sync(pd, -1);\n  }\n  gchar *columns = NULL;\n  if (find_arg_str(\"-display-columns\", &columns)) {\n    pd->columns = g_strsplit(columns, \",\", 0);\n    pd->column_separator = \"\\t\";\n    find_arg_str(\"-display-column-separator\", &pd->column_separator);\n  }\n  return TRUE;\n}\n\nstatic int dmenu_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                             unsigned int index) {\n  DmenuModePrivateData *rmpd =\n      (DmenuModePrivateData *)mode_get_private_data(sw);\n\n  /** Strip out the markup when matching. */\n  char *esc = NULL;\n  if (rmpd->cmd_list[index].permanent == TRUE) {\n    // Always match\n    return 1;\n  }\n\n  if (rmpd->do_markup) {\n    pango_parse_markup(rmpd->cmd_list[index].entry, -1, 0, NULL, &esc, NULL,\n                       NULL);\n  } else {\n    esc = rmpd->cmd_list[index].entry;\n  }\n  if (esc) {\n    //        int retv = helper_token_match ( tokens, esc );\n    int match = 1;\n    if (tokens) {\n      for (int j = 0; match && tokens[j] != NULL; j++) {\n        rofi_int_matcher *ftokens[2] = {tokens[j], NULL};\n        int test = 0;\n        test = helper_token_match(ftokens, esc);\n        if (test == tokens[j]->invert && rmpd->cmd_list[index].meta) {\n          test = helper_token_match(ftokens, rmpd->cmd_list[index].meta);\n        }\n\n        if (test == 0) {\n          match = 0;\n        }\n      }\n    }\n    if (rmpd->do_markup) {\n      g_free(esc);\n    }\n    return match;\n  }\n  return FALSE;\n}\nstatic char *dmenu_get_message(const Mode *sw) {\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n  if (pd->message) {\n    return g_strdup(pd->message);\n  }\n  return NULL;\n}\nstatic cairo_surface_t *dmenu_get_icon(const Mode *sw,\n                                       unsigned int selected_line,\n                                       unsigned int height) {\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n\n  g_return_val_if_fail(pd->cmd_list != NULL, NULL);\n  DmenuScriptEntry *dr = &(pd->cmd_list[selected_line]);\n  if (dr->icon_name == NULL) {\n    return NULL;\n  }\n\n  if (dr->icon_fetch_uid > 0) {\n    cairo_surface_t *surface = NULL;\n    gboolean query_done = rofi_icon_fetcher_get_ex(dr->icon_fetch_uid, &surface);\n\n    if (surface != NULL) {\n      return surface;\n    } else if (query_done) {\n      dr->icon_fallback_index++;\n      dr->icon_fetch_uid = 0;\n    } else {\n      return NULL;\n    }\n  }\n\n  char *current_icon = NULL;\n  if (dr->icon_name && dr->icon_fallback_index >= 0) {\n      int icon_count = g_strv_length(dr->icon_name);\n      if (dr->icon_fallback_index < icon_count) {\n          current_icon = dr->icon_name[dr->icon_fallback_index];\n      }\n  }\n  if ( current_icon ){\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(current_icon, height);\n    dr->icon_fetch_size = height;\n    dr->icon_fetch_scale = scale;\n\n  } else {\n    dr->icon_fetch_uid = 0;\n  }\n\n  return NULL;\n}\n\nstatic void dmenu_finish(DmenuModePrivateData *pd, RofiViewState *state,\n                         int retv) {\n\n  if (pd->reading_thread) {\n    // Stop listinig to new messages from reading thread.\n    if (pd->wake_source > 0) {\n      g_source_remove(pd->wake_source);\n    }\n    // signal stop.\n    write(pd->pipefd[1], \"q\", 1);\n    g_thread_join(pd->reading_thread);\n    pd->reading_thread = NULL;\n    /* empty the queue, remove idle callbacks if still pending. */\n    g_async_queue_lock(pd->async_queue);\n    Block *block = NULL;\n    while ((block = g_async_queue_try_pop_unlocked(pd->async_queue)) != NULL) {\n      g_free(block);\n    }\n    g_async_queue_unlock(pd->async_queue);\n    g_async_queue_unref(pd->async_queue);\n    pd->async_queue = NULL;\n    close(pd->pipefd[0]);\n    close(pd->pipefd[1]);\n  }\n  if (pd->fd_file != NULL) {\n    if (pd->fd_file != stdin) {\n      fclose(pd->fd_file);\n    }\n  }\n  if (retv == FALSE) {\n    rofi_set_return_code(EXIT_FAILURE);\n  } else if (retv >= 10) {\n    rofi_set_return_code(retv);\n  } else {\n    rofi_set_return_code(EXIT_SUCCESS);\n  }\n  rofi_view_set_active(NULL);\n  rofi_view_free(state);\n  mode_destroy(&dmenu_mode);\n}\n\nstatic void dmenu_print_results(DmenuModePrivateData *pd, const char *input) {\n  DmenuScriptEntry *cmd_list = pd->cmd_list;\n  int seen = FALSE;\n  for (unsigned int st = 0; st < pd->num_selected_list; st++) {\n    if ( bitget(pd->selected_list, st)) {\n      seen = TRUE;\n      rofi_output_formatted_line(pd->format, cmd_list[st].entry, st, input);\n    }\n  }\n  if (!seen) {\n    const char *cmd = input;\n    if (pd->selected_line != UINT32_MAX) {\n      cmd = cmd_list[pd->selected_line].entry;\n    }\n    if (cmd) {\n      rofi_output_formatted_line(pd->format, cmd, pd->selected_line, input);\n    }\n  }\n}\n\nstatic void dmenu_finalize(RofiViewState *state) {\n  int retv = FALSE;\n  DmenuModePrivateData *pd =\n      (DmenuModePrivateData *)rofi_view_get_mode(state)->private_data;\n\n  unsigned int cmd_list_length = pd->cmd_list_length;\n  DmenuScriptEntry *cmd_list = pd->cmd_list;\n\n  char *input = g_strdup(rofi_view_get_user_input(state));\n  pd->selected_line = rofi_view_get_selected_line(state);\n  ;\n  MenuReturn mretv = rofi_view_get_return_value(state);\n  unsigned int next_pos = rofi_view_get_next_position(state);\n  int restart = 0;\n  // Special behavior.\n  if (pd->only_selected) {\n    /**\n     * Select item mode.\n     */\n    restart = 1;\n    // Skip if no valid item is selected.\n    if ((mretv & MENU_CANCEL) == MENU_CANCEL) {\n      // In no custom mode we allow canceling.\n      restart = (find_arg(\"-only-match\") >= 0);\n    } else if (pd->selected_line != UINT32_MAX) {\n      if ((mretv & MENU_CUSTOM_ACTION) && pd->multi_select) {\n        restart = TRUE;\n        pd->loading = FALSE;\n        if (pd->num_selected_list != pd->cmd_list_length) {\n          size_t new_length = pd->cmd_list_length/32+1;\n          pd->selected_list =\n              g_realloc(pd->selected_list,sizeof(uint32_t) * (new_length));\n          if ( pd->num_selected_list == 0 ){\n            memset(pd->selected_list, 0, new_length*sizeof(uint32_t));\n          } else {\n            size_t old_length = pd->num_selected_list/32+1;\n            memset(&pd->selected_list[old_length], 0, (new_length-old_length)*sizeof(uint32_t));\n          }\n          pd->num_selected_list = pd->cmd_list_length;\n        }\n        pd->selected_count +=\n            (bitget(pd->selected_list, pd->selected_line) ? (-1) : (1));\n        bittoggle(pd->selected_list, pd->selected_line);\n        // Move to next line.\n        pd->selected_line = MIN(next_pos, cmd_list_length - 1);\n        if (pd->selected_count > 0) {\n          char *str =\n              g_strdup_printf(\"%u/%u\", pd->selected_count, pd->cmd_list_length);\n          rofi_view_set_overlay(state, str);\n          g_free(str);\n        } else {\n          rofi_view_set_overlay(state, NULL);\n        }\n      } else if ((mretv & (MENU_OK | MENU_CUSTOM_COMMAND)) &&\n                 cmd_list[pd->selected_line].entry != NULL) {\n        if (cmd_list[pd->selected_line].nonselectable == TRUE) {\n          g_free(input);\n          return;\n        }\n        dmenu_print_results(pd, input);\n        retv = TRUE;\n        if ((mretv & MENU_CUSTOM_COMMAND)) {\n          retv = 10 + (mretv & MENU_LOWER_MASK);\n        }\n        g_free(input);\n        dmenu_finish(pd, state, retv);\n        return;\n      } else {\n        pd->selected_line = next_pos - 1;\n      }\n    }\n    // Restart\n    rofi_view_restart(state);\n    rofi_view_set_selected_line(state, pd->selected_line);\n    if (!restart) {\n      dmenu_finish(pd, state, retv);\n    }\n    return;\n  }\n  // We normally do not want to restart the loop.\n  restart = FALSE;\n  // Normal mode\n  if ((mretv & MENU_OK) && pd->selected_line != UINT32_MAX &&\n      cmd_list[pd->selected_line].entry != NULL) {\n    // Check if entry is non-selectable.\n    if (cmd_list[pd->selected_line].nonselectable == TRUE) {\n      g_free(input);\n      return;\n    }\n    if ((mretv & MENU_CUSTOM_ACTION) && pd->multi_select) {\n      restart = TRUE;\n      if (pd->num_selected_list != pd->cmd_list_length) {\n          size_t new_length = pd->cmd_list_length/32+1;\n          pd->selected_list =\n              g_realloc(pd->selected_list,sizeof(uint32_t) * (new_length));\n          if ( pd->num_selected_list == 0 ){\n            memset(pd->selected_list, 0, new_length*sizeof(uint32_t));\n          } else {\n            size_t old_length = pd->num_selected_list/32+1;\n            memset(&pd->selected_list[old_length], 0, (new_length-old_length)*sizeof(uint32_t));\n          }\n          pd->num_selected_list = pd->cmd_list_length;\n      }\n      pd->selected_count +=\n          (bitget(pd->selected_list, pd->selected_line) ? (-1) : (1));\n      bittoggle(pd->selected_list, pd->selected_line);\n      // Move to next line.\n      pd->selected_line = MIN(next_pos, cmd_list_length - 1);\n      if (pd->selected_count > 0) {\n        char *str =\n            g_strdup_printf(\"%u/%u\", pd->selected_count, pd->cmd_list_length);\n        rofi_view_set_overlay(state, str);\n        g_free(str);\n      } else {\n        rofi_view_set_overlay(state, NULL);\n      }\n    } else {\n      dmenu_print_results(pd, input);\n    }\n    retv = TRUE;\n  }\n  // Custom input\n  else if ((mretv & (MENU_CUSTOM_INPUT))) {\n    dmenu_print_results(pd, input);\n\n    retv = TRUE;\n  }\n  // Quick switch with entry selected.\n  else if ((mretv & MENU_CUSTOM_COMMAND)) {\n    dmenu_print_results(pd, input);\n\n    restart = FALSE;\n    retv = 10 + (mretv & MENU_LOWER_MASK);\n  }\n  g_free(input);\n  if (restart) {\n    rofi_view_restart(state);\n    rofi_view_set_selected_line(state, pd->selected_line);\n  } else {\n    dmenu_finish(pd, state, retv);\n  }\n}\n\nint dmenu_mode_dialog(void) {\n  mode_init(&dmenu_mode);\n  MenuFlags menu_flags = MENU_NORMAL;\n  DmenuModePrivateData *pd = (DmenuModePrivateData *)dmenu_mode.private_data;\n\n  char *input = NULL;\n  unsigned int cmd_list_length = pd->cmd_list_length;\n  DmenuScriptEntry *cmd_list = pd->cmd_list;\n\n  pd->only_selected = FALSE;\n  pd->ballot_selected = \"☑ \";\n  pd->ballot_unselected = \"☐ \";\n  find_arg_str(\"-ballot-selected-str\", &(pd->ballot_selected));\n  find_arg_str(\"-ballot-unselected-str\", &(pd->ballot_unselected));\n\n  if (find_arg(\"-markup-rows\") >= 0) {\n    pd->do_markup = TRUE;\n  }\n  if (find_arg(\"-only-match\") >= 0 || find_arg(\"-no-custom\") >= 0) {\n    pd->only_selected = TRUE;\n    if (cmd_list_length == 0) {\n      return TRUE;\n    }\n  }\n  if (config.auto_select && cmd_list_length == 1) {\n    rofi_output_formatted_line(pd->format, cmd_list[0].entry, 0, config.filter);\n    return TRUE;\n  }\n  if (find_arg(\"-password\") >= 0) {\n    menu_flags |= MENU_PASSWORD;\n  }\n  /* copy filter string */\n  input = g_strdup(config.filter);\n\n  char *select = NULL;\n  find_arg_str(\"-select\", &select);\n  if (select != NULL) {\n    rofi_int_matcher **tokens =\n        helper_tokenize(select, parse_case_sensitivity(select));\n    unsigned int i = 0;\n    for (i = 0; i < cmd_list_length; i++) {\n      if (helper_token_match(tokens, cmd_list[i].entry)) {\n        pd->selected_line = i;\n        break;\n      }\n    }\n    helper_tokenize_free(tokens);\n  }\n  if (find_arg(\"-dump\") >= 0) {\n    char *filter = config.filter ? config.filter : \"\";\n    rofi_int_matcher **tokens =\n        helper_tokenize(filter, parse_case_sensitivity(filter));\n    unsigned int i = 0;\n    for (i = 0; i < cmd_list_length; i++) {\n      if (tokens == NULL || helper_token_match(tokens, cmd_list[i].entry)) {\n        rofi_output_formatted_line(pd->format, cmd_list[i].entry, i,\n                                   config.filter);\n      }\n    }\n    helper_tokenize_free(tokens);\n    dmenu_mode_free(&dmenu_mode);\n    g_free(input);\n    return TRUE;\n  }\n  find_arg_str(\"-p\", &(dmenu_mode.display_name));\n  RofiViewState *state =\n      rofi_view_create(&dmenu_mode, input, menu_flags, dmenu_finalize);\n\n  if (find_arg(\"-keep-right\") >= 0) {\n    rofi_view_ellipsize_listview(state, PANGO_ELLIPSIZE_START);\n  }\n  char *ellipsize_mode = NULL;\n  if (find_arg_str(\"-ellipsize-mode\", &ellipsize_mode) >= 0) {\n    if (ellipsize_mode) {\n      if (g_ascii_strcasecmp(ellipsize_mode, \"start\") == 0) {\n        rofi_view_ellipsize_listview(state, PANGO_ELLIPSIZE_START);\n      } else if (g_ascii_strcasecmp(ellipsize_mode, \"middle\") == 0) {\n        rofi_view_ellipsize_listview(state, PANGO_ELLIPSIZE_MIDDLE);\n      } else if (g_ascii_strcasecmp(ellipsize_mode, \"end\") == 0) {\n        rofi_view_ellipsize_listview(state, PANGO_ELLIPSIZE_END);\n      } else {\n        g_warning(\"Unrecognized ellipsize mode: '%s'\", ellipsize_mode);\n      }\n    }\n  }\n  rofi_view_set_selected_line(state, pd->selected_line);\n  rofi_view_set_active(state);\n  if (pd->loading) {\n    rofi_view_set_overlay(state, \"Loading.. \");\n  }\n\n  return FALSE;\n}\n\nvoid print_dmenu_options(void) {\n  int is_term = isatty(fileno(stdout));\n  print_help_msg(\n      \"-mesg\", \"[string]\",\n      \"Print a small user message under the prompt (uses pango markup)\", NULL,\n      is_term);\n  print_help_msg(\"-p\", \"[string]\", \"Prompt to display left of entry field\",\n                 NULL, is_term);\n  print_help_msg(\"-selected-row\", \"[integer]\", \"Select row\", NULL, is_term);\n  print_help_msg(\"-format\", \"[string]\", \"Output format string\", \"s\", is_term);\n  print_help_msg(\"-u\", \"[list]\", \"List of row indexes to mark urgent\", NULL,\n                 is_term);\n  print_help_msg(\"-a\", \"[list]\", \"List of row indexes to mark active\", NULL,\n                 is_term);\n  print_help_msg(\"-l\", \"[integer] \", \"Number of rows to display\", NULL,\n                 is_term);\n  print_help_msg(\"-window-title\", \"[string] \", \"Set the dmenu window title\",\n                 NULL, is_term);\n  print_help_msg(\"-i\", \"\", \"Set filter to be case insensitive\", NULL, is_term);\n  print_help_msg(\"-only-match\", \"\",\n                 \"Force selection to be given entry, disallow no match\", NULL,\n                 is_term);\n  print_help_msg(\"-no-custom\", \"\", \"Don't accept custom entry, allow no match\",\n                 NULL, is_term);\n  print_help_msg(\"-select\", \"[string]\", \"Select the first row that matches\",\n                 NULL, is_term);\n  print_help_msg(\"-password\", \"\",\n                 \"Do not show what the user inputs. Show '*' instead.\", NULL,\n                 is_term);\n  print_help_msg(\"-markup-rows\", \"\",\n                 \"Allow and render pango markup as input data.\", NULL, is_term);\n  print_help_msg(\"-sep\", \"[char]\", \"Element separator.\", \"'\\\\n'\", is_term);\n  print_help_msg(\"-input\", \"[filename]\",\n                 \"Read input from file instead from standard input.\", NULL,\n                 is_term);\n  print_help_msg(\"-sync\", \"\",\n                 \"Force dmenu to first read all input data, then show dialog.\",\n                 NULL, is_term);\n  print_help_msg(\"-w\", \"windowid\", \"Position over window with X11 windowid.\",\n                 NULL, is_term);\n  print_help_msg(\"-keep-right\", \"\", \"Set ellipsize to end.\", NULL, is_term);\n  print_help_msg(\"-display-columns\", \"\", \"Only show the selected columns\", NULL,\n                 is_term);\n  print_help_msg(\"-display-column-separator\", \"\\t\",\n                 \"Separator to use to split columns (regex)\", NULL, is_term);\n  print_help_msg(\"-ballot-selected-str\", \"\\t\",\n                 \"When multi-select is enabled prefix this string when element \"\n                 \"is selected.\",\n                 NULL, is_term);\n  print_help_msg(\"-ballot-unselected-str\", \"\\t\",\n                 \"When multi-select is enabled prefix this string when element \"\n                 \"is not selected.\",\n                 NULL, is_term);\n  print_help_msg(\"-ellipsize-mode\", \"end\",\n                 \"Set ellipsize mode(start | middle | end).\", NULL, is_term);\n}\n"
  },
  {
    "path": "source/modes/drun.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#define G_LOG_DOMAIN \"Modes.DRun\"\n#include \"config.h\"\n/** The log domain of this dialog. */\n#include \"glib.h\"\n\n#ifdef ENABLE_DRUN\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <dirent.h>\n#include <errno.h>\n#include <limits.h>\n#include <signal.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <gio/gio.h>\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"history.h\"\n#include \"mode-private.h\"\n#include \"modes/drun.h\"\n#include \"modes/filebrowser.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"timings.h\"\n#include \"widgets/textbox.h\"\n\n#include \"rofi-icon-fetcher.h\"\n\n/** The filename of the history cache file. */\n#define DRUN_CACHE_FILE \"rofi3.druncache\"\n\n/** The filename of the drun quick-load cache file. */\n#define DRUN_DESKTOP_CACHE_FILE \"rofi-drun-desktop.cache\"\n\n/** Maximum string lengths we support in our drun cache is 10kbyte */\n#define DRUN_MAX_STRING_LENGTH (10 * 1024 * 1024)\n\n#define DRUN_MAX_NUM_ENTRIES (256 * 1024)\n\n/** The group name used in desktop files */\nchar *DRUN_GROUP_NAME = \"Desktop Entry\";\n\n/**\n *The Internal data structure for the drun mode.\n */\ntypedef struct _DRunModePrivateData DRunModePrivateData;\n\n/**\n * Used to determine the type of desktop file.\n */\ntypedef enum {\n  /** Unknown. */\n  DRUN_DESKTOP_ENTRY_TYPE_UNDETERMINED = 0,\n  /** Application */\n  DRUN_DESKTOP_ENTRY_TYPE_APPLICATION,\n  /** Link */\n  DRUN_DESKTOP_ENTRY_TYPE_LINK,\n  /** KDE Service File */\n  DRUN_DESKTOP_ENTRY_TYPE_SERVICE,\n  /** Directory */\n  DRUN_DESKTOP_ENTRY_TYPE_DIRECTORY,\n} DRunDesktopEntryType;\n\n/**\n * Store extra information about the entry.\n * Currently the executable and if it should run in terminal.\n */\ntypedef struct {\n  DRunModePrivateData *pd;\n  /* category */\n  char *action;\n  /* Root */\n  char *root;\n  /* Path to desktop file */\n  char *path;\n  /* Application id (.desktop filename) */\n  char *app_id;\n  /* Desktop id */\n  char *desktop_id;\n  /* Icon stuff */\n  char *icon_name;\n  /* Icon size is used to indicate what size is requested by the\n   * gui. secondary it indicates if the request for a lookup has\n   * been issued (0 not issued )\n   */\n  int icon_size;\n  /* Surface holding the icon. */\n  cairo_surface_t *icon;\n  /* Executable - for Application entries only */\n  char *exec;\n  /* Name of the Entry */\n  char *name;\n  /* Generic Name */\n  char *generic_name;\n  /* Categories */\n  char **categories;\n  /* Keywords */\n  char **keywords;\n  /* Comments */\n  char *comment;\n  /* Url */\n  char *url;\n  /* Underlying key-file. */\n  GKeyFile *key_file;\n  /* Used for sorting. */\n  gint sort_index;\n  /* UID for the icon to display */\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  /* Type of desktop file */\n  DRunDesktopEntryType type;\n} DRunModeEntry;\n\ntypedef struct {\n  const char *entry_field_name;\n  gboolean enabled_match;\n  gboolean enabled_display;\n} DRunEntryField;\n\n/** The fields that can be displayed and used for matching */\ntypedef enum {\n  /** Name */\n  DRUN_MATCH_FIELD_NAME,\n  /** Generic Name */\n  DRUN_MATCH_FIELD_GENERIC,\n  /** Exec */\n  DRUN_MATCH_FIELD_EXEC,\n  /** List of categories */\n  DRUN_MATCH_FIELD_CATEGORIES,\n  /** List of keywords */\n  DRUN_MATCH_FIELD_KEYWORDS,\n  /** Comment */\n  DRUN_MATCH_FIELD_COMMENT,\n  /** Url */\n  DRUN_MATCH_FIELD_URL,\n  /** Number of DRunMatchingFields entries. */\n  DRUN_MATCH_NUM_FIELDS,\n} DRunMatchingFields;\n\n/** Stores what fields should be matched on user input. based on user setting.\n */\nstatic DRunEntryField matching_entry_fields[DRUN_MATCH_NUM_FIELDS] = {\n    {\n        .entry_field_name = \"name\",\n        .enabled_match = TRUE,\n        .enabled_display = TRUE,\n    },\n    {\n        .entry_field_name = \"generic\",\n        .enabled_match = TRUE,\n        .enabled_display = TRUE,\n    },\n    {\n        .entry_field_name = \"exec\",\n        .enabled_match = TRUE,\n        .enabled_display = TRUE,\n    },\n    {\n        .entry_field_name = \"categories\",\n        .enabled_match = TRUE,\n        .enabled_display = TRUE,\n    },\n    {\n        .entry_field_name = \"keywords\",\n        .enabled_match = TRUE,\n        .enabled_display = TRUE,\n    },\n    {\n        .entry_field_name = \"comment\",\n        .enabled_match = FALSE,\n        .enabled_display = FALSE,\n    },\n    {\n        .entry_field_name = \"url\",\n        .enabled_match = FALSE,\n        .enabled_display = FALSE,\n    }};\n\nstruct _DRunModePrivateData {\n  DRunModeEntry *entry_list;\n  unsigned int cmd_list_length;\n  unsigned int cmd_list_length_actual;\n  // List of disabled entries.\n  GHashTable *disabled_entries;\n  unsigned int disabled_entries_length;\n  unsigned int expected_line_height;\n\n  char **show_categories;\n  char **exclude_categories;\n\n  // Theme\n  const gchar *icon_theme;\n  // DE\n  gchar **current_desktop_list;\n\n  gboolean file_complete;\n  Mode *completer;\n  char *old_completer_input;\n  uint32_t selected_line;\n  char *old_input;\n\n  gboolean disable_dbusactivate;\n};\n\nstruct RegexEvalArg {\n  DRunModeEntry *e;\n  const char *path;\n  gboolean success;\n};\nstatic void drun_entry_clear(DRunModeEntry *e);\n\nstatic gboolean drun_helper_eval_cb(const GMatchInfo *info, GString *res,\n                                    gpointer data) {\n  // TODO quoting is not right? Find description not very clear, need to check.\n  struct RegexEvalArg *e = (struct RegexEvalArg *)data;\n\n  gchar *match;\n  // Get the match\n  match = g_match_info_fetch(info, 0);\n  if (match != NULL) {\n    switch (match[1]) {\n    case 'f':\n    case 'F':\n    case 'u':\n    case 'U':\n      if (e->path) {\n        g_string_append(res, e->path);\n      }\n      break;\n    // Unsupported\n    case 'i':\n      // TODO\n      if (e->e && e->e->icon) {\n        g_string_append_printf(res, \"--icon %s\", e->e->icon_name);\n      }\n      break;\n    // Deprecated\n    case 'd':\n    case 'D':\n    case 'n':\n    case 'N':\n    case 'v':\n    case 'm':\n      break;\n    case '%':\n      g_string_append(res, \"%\");\n      break;\n    case 'k':\n      if (e->e->path) {\n        char *esc = g_shell_quote(e->e->path);\n        g_string_append(res, esc);\n        g_free(esc);\n      }\n      break;\n    case 'c':\n      if (e->e->name) {\n        char *esc = g_shell_quote(e->e->name);\n        g_string_append(res, esc);\n        g_free(esc);\n      }\n      break;\n    // Invalid, this entry should not be processed -> throw error.\n    default:\n      e->success = FALSE;\n      g_free(match);\n      return TRUE;\n    }\n    g_free(match);\n  }\n  // Continue replacement.\n  return FALSE;\n}\nstatic void launch_link_entry(DRunModeEntry *e) {\n  if (e->key_file == NULL) {\n    GKeyFile *kf = g_key_file_new();\n    GError *error = NULL;\n    gboolean res = g_key_file_load_from_file(kf, e->path, 0, &error);\n    if (res) {\n      e->key_file = kf;\n    } else {\n      g_warning(\"[%s] [%s] Failed to parse desktop file because: %s.\",\n                e->app_id, e->path, error->message);\n      g_error_free(error);\n      g_key_file_free(kf);\n      return;\n    }\n  }\n\n  gchar *url = g_key_file_get_string(e->key_file, e->action, \"URL\", NULL);\n  if (url == NULL || strlen(url) == 0) {\n    g_warning(\"[%s] [%s] No URL found.\", e->app_id, e->path);\n    g_free(url);\n    return;\n  }\n\n  gsize command_len = strlen(config.drun_url_launcher) + strlen(url) +\n                      2; // space + terminator = 2\n  gchar *command = g_newa(gchar, command_len);\n  g_snprintf(command, command_len, \"%s %s\", config.drun_url_launcher, url);\n  g_free(url);\n\n  g_debug(\"Link launch command: |%s|\", command);\n  if (helper_execute_command(NULL, command, FALSE, NULL)) {\n    char *path = g_build_filename(cache_dir, DRUN_CACHE_FILE, NULL);\n    // Store it based on the unique identifiers (desktop_id).\n    history_set(path, e->desktop_id);\n    g_free(path);\n  }\n}\nstatic gchar *app_path_for_id(const gchar *app_id) {\n  gchar *path;\n  gint i;\n\n  path = g_strconcat(\"/\", app_id, NULL);\n  for (i = 0; path[i]; i++) {\n    if (path[i] == '.')\n      path[i] = '/';\n    if (path[i] == '-')\n      path[i] = '_';\n  }\n\n  return path;\n}\nstatic GVariant *app_get_platform_data(void) {\n  GVariantBuilder builder;\n  const gchar *startup_id;\n\n  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);\n\n  if ((startup_id = g_getenv(\"DESKTOP_STARTUP_ID\")))\n    g_variant_builder_add(&builder, \"{sv}\", \"desktop-startup-id\",\n                          g_variant_new_string(startup_id));\n\n  if ((startup_id = g_getenv(\"XDG_ACTIVATION_TOKEN\")))\n    g_variant_builder_add(&builder, \"{sv}\", \"activation-token\",\n                          g_variant_new_string(startup_id));\n\n  return g_variant_builder_end(&builder);\n}\n\nstatic gboolean exec_dbus_entry(DRunModeEntry *e, const char *path) {\n  GVariantBuilder files;\n  GDBusConnection *session;\n  GError *error = NULL;\n  gchar *object_path;\n  GVariant *result;\n  GVariant *params = NULL;\n  const char *method = \"Activate\";\n  g_debug(\"Trying to launch desktop file using dbus activation.\");\n\n  session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);\n  if (!session) {\n    g_warning(\"unable to connect to D-Bus: %s\\n\", error->message);\n    g_error_free(error);\n    return FALSE;\n  }\n\n  object_path = app_path_for_id(e->app_id);\n\n  g_variant_builder_init(&files, G_VARIANT_TYPE_STRING_ARRAY);\n\n  if (path != NULL) {\n    method = \"Open\";\n    params = g_variant_new(\"(as@a{sv})\", &files, app_get_platform_data());\n  } else {\n    params = g_variant_new(\"(@a{sv})\", app_get_platform_data());\n  }\n  if (path) {\n    GFile *file = g_file_new_for_commandline_arg(path);\n    g_variant_builder_add_value(\n        &files, g_variant_new_take_string(g_file_get_uri(file)));\n    g_object_unref(file);\n  }\n  // Wait 1500ms, otherwise assume failed.\n  result = NULL;\n  if (g_dbus_is_name(e->app_id)) {\n    result = g_dbus_connection_call_sync(\n        session, e->app_id, object_path, \"org.freedesktop.Application\", method,\n        params, G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE, 1500, NULL,\n        &error);\n  }\n  g_free(object_path);\n\n  if (result) {\n    g_variant_unref(result);\n  } else {\n    if (error != NULL) {\n      g_warning(\"error sending %s message to application: %s\\n\", \"Open\",\n                error->message);\n      g_error_free(error);\n    }\n    g_object_unref(session);\n    return FALSE;\n  }\n  g_object_unref(session);\n  return TRUE;\n}\n\nstatic void exec_cmd_entry(DRunModePrivateData *pd, DRunModeEntry *e,\n                           const char *path) {\n  GError *error = NULL;\n  GRegex *reg = g_regex_new(\"%[a-zA-Z%]\", 0, 0, &error);\n  if (error != NULL) {\n    g_warning(\"Internal error, failed to create regex: %s.\", error->message);\n    g_error_free(error);\n    return;\n  }\n  struct RegexEvalArg earg = {.e = e, .path = path, .success = TRUE};\n  char *str = g_regex_replace_eval(reg, e->exec, -1, 0, 0, drun_helper_eval_cb,\n                                   &earg, &error);\n  if (error != NULL) {\n    g_warning(\"Internal error, failed replace field codes: %s.\",\n              error->message);\n    g_error_free(error);\n    return;\n  }\n  g_regex_unref(reg);\n  if (earg.success == FALSE) {\n    g_warning(\"Invalid field code in Exec line: %s.\", e->exec);\n    ;\n    return;\n  }\n  if (str == NULL) {\n    g_warning(\"Nothing to execute after processing: %s.\", e->exec);\n    ;\n    return;\n  }\n  g_debug(\"Parsed command: |%s| into |%s|.\", e->exec, str);\n\n  if (e->key_file == NULL) {\n    GKeyFile *kf = g_key_file_new();\n    GError *key_error = NULL;\n    gboolean res = g_key_file_load_from_file(kf, e->path, 0, &key_error);\n    if (res) {\n      e->key_file = kf;\n    } else {\n      g_warning(\"[%s] [%s] Failed to parse desktop file because: %s.\",\n                e->app_id, e->path, key_error->message);\n      g_error_free(key_error);\n      g_key_file_free(kf);\n\n      return;\n    }\n  }\n\n  const gchar *fp = g_strstrip(str);\n  gchar *exec_path =\n      g_key_file_get_string(e->key_file, e->action, \"Path\", NULL);\n  if (exec_path != NULL && strlen(exec_path) == 0) {\n    // If it is empty, ignore this property. (#529)\n    g_free(exec_path);\n    exec_path = NULL;\n  }\n\n  RofiHelperExecuteContext context = {\n      .name = e->name,\n      .icon = e->icon_name,\n      .app_id = e->app_id,\n  };\n  gboolean sn =\n      g_key_file_get_boolean(e->key_file, e->action, \"StartupNotify\", NULL);\n  gchar *wmclass = NULL;\n  if (sn &&\n      g_key_file_has_key(e->key_file, e->action, \"StartupWMClass\", NULL)) {\n    context.wmclass = wmclass =\n        g_key_file_get_string(e->key_file, e->action, \"StartupWMClass\", NULL);\n  }\n\n  /**\n   * If its required to launch via dbus, do that.\n   */\n  gboolean launched = FALSE;\n  if (!(pd->disable_dbusactivate)) {\n    if (g_key_file_get_boolean(e->key_file, e->action, \"DBusActivatable\",\n                               NULL)) {\n      printf(\"DBus launch\\n\");\n      launched = exec_dbus_entry(e, path);\n    }\n  }\n  if (launched == FALSE) {\n    /** Fallback to old style if not set. */\n\n    // Returns false if not found, if key not found, we don't want run in\n    // terminal.\n    gboolean terminal =\n        g_key_file_get_boolean(e->key_file, e->action, \"Terminal\", NULL);\n    launched =\n        helper_execute_command(exec_path, fp, terminal, sn ? &context : NULL);\n  }\n  if (launched == TRUE) {\n    char *drun_cach_path = g_build_filename(cache_dir, DRUN_CACHE_FILE, NULL);\n    // Store it based on the unique identifiers (desktop_id).\n    history_set(drun_cach_path, e->desktop_id);\n    g_free(drun_cach_path);\n  }\n  g_free(wmclass);\n  g_free(exec_path);\n  g_free(str);\n}\n\nstatic gboolean rofi_strv_contains(const char *const *categories,\n                                   const char *const *field) {\n  for (int i = 0; categories && categories[i]; i++) {\n    for (int j = 0; field[j]; j++) {\n      if (g_str_equal(categories[i], field[j])) {\n        return TRUE;\n      }\n    }\n  }\n  return FALSE;\n}\n/**\n * This function absorbs/freeś path, so this is no longer available afterwards.\n */\nstatic void read_desktop_file(DRunModePrivateData *pd, const char *root,\n                              const char *path, const gchar *basename,\n                              const char *action) {\n  DRunDesktopEntryType desktop_entry_type =\n      DRUN_DESKTOP_ENTRY_TYPE_UNDETERMINED;\n  int parse_action = (config.drun_show_actions && action != DRUN_GROUP_NAME);\n  // Create ID on stack.\n  // We know strlen (path ) > strlen(root)+1\n  const ssize_t id_len = strlen(path) - strlen(root);\n  char id[id_len];\n  g_strlcpy(id, &(path[strlen(root) + 1]), id_len);\n  for (int index = 0; index < id_len; index++) {\n    if (id[index] == '/') {\n      id[index] = '-';\n    }\n  }\n\n  // Check if item is on disabled list.\n  if (g_hash_table_contains(pd->disabled_entries, id) && !parse_action) {\n    g_debug(\"[%s] [%s] Skipping, was previously seen.\", id, path);\n    return;\n  }\n  GKeyFile *kf = g_key_file_new();\n  GError *error = NULL;\n  gboolean res = g_key_file_load_from_file(kf, path, 0, &error);\n  // If error, skip to next entry\n  if (!res) {\n    g_debug(\"[%s] [%s] Failed to parse desktop file because: %s.\", id, path,\n            error->message);\n    g_error_free(error);\n    g_key_file_free(kf);\n    return;\n  }\n\n  if (g_key_file_has_group(kf, action) == FALSE) {\n    // No type? ignore.\n    g_debug(\"[%s] [%s] Invalid desktop file: No %s group\", id, path, action);\n    g_key_file_free(kf);\n    return;\n  }\n  // Skip non Application entries.\n  gchar *key = g_key_file_get_string(kf, DRUN_GROUP_NAME, \"Type\", NULL);\n  if (key == NULL) {\n    // No type? ignore.\n    g_debug(\"[%s] [%s] Invalid desktop file: No type indicated\", id, path);\n    g_key_file_free(kf);\n    return;\n  }\n  if (!g_strcmp0(key, \"Application\")) {\n    desktop_entry_type = DRUN_DESKTOP_ENTRY_TYPE_APPLICATION;\n  } else if (!g_strcmp0(key, \"Link\")) {\n    desktop_entry_type = DRUN_DESKTOP_ENTRY_TYPE_LINK;\n  } else if (!g_strcmp0(key, \"Service\")) {\n    desktop_entry_type = DRUN_DESKTOP_ENTRY_TYPE_SERVICE;\n    g_debug(\"Service file detected.\");\n  } else {\n    g_debug(\n        \"[%s] [%s] Skipping desktop file: Not of type Application or Link (%s)\",\n        id, path, key);\n    g_free(key);\n    g_key_file_free(kf);\n    return;\n  }\n  g_free(key);\n\n  // Name key is required.\n  if (!g_key_file_has_key(kf, DRUN_GROUP_NAME, \"Name\", NULL)) {\n    g_debug(\"[%s] [%s] Invalid desktop file: no 'Name' key present.\", id, path);\n    g_key_file_free(kf);\n    return;\n  }\n\n  // Skip hidden entries.\n  if (g_key_file_get_boolean(kf, DRUN_GROUP_NAME, \"Hidden\", NULL)) {\n    g_debug(\n        \"[%s] [%s] Adding desktop file to disabled list: 'Hidden' key is true\",\n        id, path);\n    g_key_file_free(kf);\n    g_hash_table_add(pd->disabled_entries, g_strdup(id));\n    return;\n  }\n  if (pd->current_desktop_list) {\n    gboolean show = TRUE;\n    // If the DE is set, check the keys.\n    if (g_key_file_has_key(kf, DRUN_GROUP_NAME, \"OnlyShowIn\", NULL)) {\n      gsize llength = 0;\n      show = FALSE;\n      gchar **list = g_key_file_get_string_list(kf, DRUN_GROUP_NAME,\n                                                \"OnlyShowIn\", &llength, NULL);\n      if (list) {\n        for (gsize lcd = 0; !show && pd->current_desktop_list[lcd]; lcd++) {\n          for (gsize lle = 0; !show && lle < llength; lle++) {\n            show = (g_strcmp0(pd->current_desktop_list[lcd], list[lle]) == 0);\n          }\n        }\n        g_strfreev(list);\n      }\n    }\n    if (show && g_key_file_has_key(kf, DRUN_GROUP_NAME, \"NotShowIn\", NULL)) {\n      gsize llength = 0;\n      gchar **list = g_key_file_get_string_list(kf, DRUN_GROUP_NAME,\n                                                \"NotShowIn\", &llength, NULL);\n      if (list) {\n        for (gsize lcd = 0; show && pd->current_desktop_list[lcd]; lcd++) {\n          for (gsize lle = 0; show && lle < llength; lle++) {\n            show = !(g_strcmp0(pd->current_desktop_list[lcd], list[lle]) == 0);\n          }\n        }\n        g_strfreev(list);\n      }\n    }\n\n    if (!show) {\n      g_debug(\"[%s] [%s] Adding desktop file to disabled list: \"\n              \"'OnlyShowIn'/'NotShowIn' keys don't match current desktop\",\n              id, path);\n      g_key_file_free(kf);\n      g_hash_table_add(pd->disabled_entries, g_strdup(id));\n      return;\n    }\n  }\n  // Skip entries that have NoDisplay set.\n  if (g_key_file_get_boolean(kf, DRUN_GROUP_NAME, \"NoDisplay\", NULL)) {\n    g_debug(\"[%s] [%s] Adding desktop file to disabled list: 'NoDisplay' key \"\n            \"is true\",\n            id, path);\n    g_key_file_free(kf);\n    g_hash_table_add(pd->disabled_entries, g_strdup(id));\n    return;\n  }\n\n  // We need Exec, don't support DBusActivatable\n  if (desktop_entry_type == DRUN_DESKTOP_ENTRY_TYPE_APPLICATION &&\n      !g_key_file_has_key(kf, DRUN_GROUP_NAME, \"Exec\", NULL)) {\n    g_debug(\"[%s] [%s] Unsupported desktop file: no 'Exec' key present for \"\n            \"type Application.\",\n            id, path);\n    g_key_file_free(kf);\n    return;\n  }\n  if (desktop_entry_type == DRUN_DESKTOP_ENTRY_TYPE_SERVICE &&\n      !g_key_file_has_key(kf, DRUN_GROUP_NAME, \"Exec\", NULL)) {\n    g_debug(\"[%s] [%s] Unsupported desktop file: no 'Exec' key present for \"\n            \"type Service.\",\n            id, path);\n    g_key_file_free(kf);\n    return;\n  }\n  if (desktop_entry_type == DRUN_DESKTOP_ENTRY_TYPE_LINK &&\n      !g_key_file_has_key(kf, DRUN_GROUP_NAME, \"URL\", NULL)) {\n    g_debug(\"[%s] [%s] Unsupported desktop file: no 'URL' key present for type \"\n            \"Link.\",\n            id, path);\n    g_key_file_free(kf);\n    return;\n  }\n\n  if (g_key_file_has_key(kf, DRUN_GROUP_NAME, \"TryExec\", NULL)) {\n    char *te = g_key_file_get_string(kf, DRUN_GROUP_NAME, \"TryExec\", NULL);\n    if (!g_path_is_absolute(te)) {\n      char *fp = g_find_program_in_path(te);\n      if (fp == NULL) {\n        g_free(te);\n        g_key_file_free(kf);\n        return;\n      }\n      g_free(fp);\n    } else {\n      if (g_file_test(te, G_FILE_TEST_IS_EXECUTABLE) == FALSE) {\n        g_free(te);\n        g_key_file_free(kf);\n        return;\n      }\n    }\n    g_free(te);\n  }\n\n  char **categories = NULL;\n  if (pd->show_categories) {\n    categories = g_key_file_get_locale_string_list(\n        kf, DRUN_GROUP_NAME, \"Categories\", NULL, NULL, NULL);\n    if (!rofi_strv_contains((const char *const *)categories,\n                            (const char *const *)pd->show_categories)) {\n      g_strfreev(categories);\n      g_key_file_free(kf);\n      return;\n    }\n  }\n\n  if (pd->exclude_categories) {\n    if (categories == NULL) {\n      categories = g_key_file_get_locale_string_list(\n          kf, DRUN_GROUP_NAME, \"Categories\", NULL, NULL, NULL);\n    }\n    if (rofi_strv_contains((const char *const *)categories,\n                           (const char *const *)pd->exclude_categories)) {\n      g_strfreev(categories);\n      g_key_file_free(kf);\n      return;\n    }\n  }\n\n  size_t nl = ((pd->cmd_list_length) + 1);\n  if (nl >= pd->cmd_list_length_actual) {\n    pd->cmd_list_length_actual += 256;\n    pd->entry_list = g_realloc(pd->entry_list, pd->cmd_list_length_actual *\n                                                   sizeof(*(pd->entry_list)));\n  }\n  // Make sure order is preserved, this will break when cmd_list_length is\n  // bigger then INT_MAX. This is not likely to happen.\n  if (G_UNLIKELY(pd->cmd_list_length > INT_MAX)) {\n    // Default to smallest value.\n    pd->entry_list[pd->cmd_list_length].sort_index = INT_MIN;\n  } else {\n    pd->entry_list[pd->cmd_list_length].sort_index = -nl;\n  }\n  pd->entry_list[pd->cmd_list_length].icon_size = 0;\n  pd->entry_list[pd->cmd_list_length].icon_fetch_uid = 0;\n  pd->entry_list[pd->cmd_list_length].icon_fetch_size = 0;\n  pd->entry_list[pd->cmd_list_length].icon_fetch_scale = 0;\n  pd->entry_list[pd->cmd_list_length].root = g_strdup(root);\n  pd->entry_list[pd->cmd_list_length].path = g_strdup(path);\n  pd->entry_list[pd->cmd_list_length].desktop_id = g_strdup(id);\n  pd->entry_list[pd->cmd_list_length].app_id =\n      g_strndup(basename, strlen(basename) - strlen(\".desktop\"));\n  gchar *n =\n      g_key_file_get_locale_string(kf, DRUN_GROUP_NAME, \"Name\", NULL, NULL);\n\n  if (action != DRUN_GROUP_NAME) {\n    gchar *na = g_key_file_get_locale_string(kf, action, \"Name\", NULL, NULL);\n    gchar *l = g_strdup_printf(\"%s - %s\", n, na);\n    g_free(n);\n    n = l;\n  }\n  pd->entry_list[pd->cmd_list_length].name = n;\n  pd->entry_list[pd->cmd_list_length].action = DRUN_GROUP_NAME;\n  gchar *gn = g_key_file_get_locale_string(kf, DRUN_GROUP_NAME, \"GenericName\",\n                                           NULL, NULL);\n  pd->entry_list[pd->cmd_list_length].generic_name = gn;\n  if (matching_entry_fields[DRUN_MATCH_FIELD_KEYWORDS].enabled_match ||\n      matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled_display) {\n    pd->entry_list[pd->cmd_list_length].keywords =\n        g_key_file_get_locale_string_list(kf, DRUN_GROUP_NAME, \"Keywords\", NULL,\n                                          NULL, NULL);\n  } else {\n    pd->entry_list[pd->cmd_list_length].keywords = NULL;\n  }\n\n  if (matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled_match ||\n      matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled_display) {\n    if (categories) {\n      pd->entry_list[pd->cmd_list_length].categories = categories;\n      categories = NULL;\n    } else {\n      pd->entry_list[pd->cmd_list_length].categories =\n          g_key_file_get_locale_string_list(kf, DRUN_GROUP_NAME, \"Categories\",\n                                            NULL, NULL, NULL);\n    }\n  } else {\n    pd->entry_list[pd->cmd_list_length].categories = NULL;\n  }\n  g_strfreev(categories);\n\n  pd->entry_list[pd->cmd_list_length].type = desktop_entry_type;\n  if (desktop_entry_type == DRUN_DESKTOP_ENTRY_TYPE_APPLICATION ||\n      desktop_entry_type == DRUN_DESKTOP_ENTRY_TYPE_SERVICE) {\n    pd->entry_list[pd->cmd_list_length].exec =\n        g_key_file_get_string(kf, action, \"Exec\", NULL);\n  } else {\n    pd->entry_list[pd->cmd_list_length].exec = NULL;\n  }\n\n  if (matching_entry_fields[DRUN_MATCH_FIELD_COMMENT].enabled_match ||\n      matching_entry_fields[DRUN_MATCH_FIELD_COMMENT].enabled_display) {\n    pd->entry_list[pd->cmd_list_length].comment = g_key_file_get_locale_string(\n        kf, DRUN_GROUP_NAME, \"Comment\", NULL, NULL);\n  } else {\n    pd->entry_list[pd->cmd_list_length].comment = NULL;\n  }\n  if (matching_entry_fields[DRUN_MATCH_FIELD_URL].enabled_match ||\n      matching_entry_fields[DRUN_MATCH_FIELD_URL].enabled_display) {\n    pd->entry_list[pd->cmd_list_length].url =\n        g_key_file_get_locale_string(kf, DRUN_GROUP_NAME, \"URL\", NULL, NULL);\n  } else {\n    pd->entry_list[pd->cmd_list_length].url = NULL;\n  }\n  pd->entry_list[pd->cmd_list_length].icon_name =\n      g_key_file_get_locale_string(kf, DRUN_GROUP_NAME, \"Icon\", NULL, NULL);\n  pd->entry_list[pd->cmd_list_length].icon = NULL;\n\n  // Keep keyfile around.\n  pd->entry_list[pd->cmd_list_length].key_file = kf;\n  // We don't want to parse items with this id anymore.\n  g_hash_table_add(pd->disabled_entries, g_strdup(id));\n  g_debug(\"[%s] Using file %s.\", id, path);\n  (pd->cmd_list_length)++;\n\n  if (!parse_action) {\n    gsize actions_length = 0;\n    char **actions = g_key_file_get_string_list(kf, DRUN_GROUP_NAME, \"Actions\",\n                                                &actions_length, NULL);\n    for (gsize iter = 0; iter < actions_length; iter++) {\n      char *new_action = g_strdup_printf(\"Desktop Action %s\", actions[iter]);\n      read_desktop_file(pd, root, path, basename, new_action);\n      g_free(new_action);\n    }\n    g_strfreev(actions);\n  }\n  return;\n}\n\n/**\n * Internal spider used to get list of executables.\n */\nstatic void walk_dir(DRunModePrivateData *pd, const char *root,\n                     const char *dirname, const gboolean recursive) {\n  DIR *dir;\n\n  g_debug(\"Checking directory %s for desktop files.\", dirname);\n  dir = opendir(dirname);\n  if (dir == NULL) {\n    return;\n  }\n\n  struct dirent *file;\n  gchar *filename = NULL;\n  struct stat st;\n  while ((file = readdir(dir)) != NULL) {\n    if (file->d_name[0] == '.') {\n      continue;\n    }\n    switch (file->d_type) {\n    case DT_LNK:\n    case DT_REG:\n    case DT_DIR:\n    case DT_UNKNOWN:\n      filename = g_build_filename(dirname, file->d_name, NULL);\n      break;\n    default:\n      continue;\n    }\n\n    // On a link, or if FS does not support providing this information\n    // Fallback to stat method.\n    if (file->d_type == DT_LNK || file->d_type == DT_UNKNOWN) {\n      file->d_type = DT_UNKNOWN;\n      if (stat(filename, &st) == 0) {\n        if (S_ISDIR(st.st_mode)) {\n          file->d_type = DT_DIR;\n        } else if (S_ISREG(st.st_mode)) {\n          file->d_type = DT_REG;\n        }\n      }\n    }\n\n    switch (file->d_type) {\n    case DT_REG:\n      // Skip files not ending on .desktop.\n      if (g_str_has_suffix(file->d_name, \".desktop\")) {\n        read_desktop_file(pd, root, filename, file->d_name, DRUN_GROUP_NAME);\n      }\n      break;\n    case DT_DIR:\n      if (recursive) {\n        walk_dir(pd, root, filename, recursive);\n      }\n      break;\n    default:\n      break;\n    }\n    g_free(filename);\n  }\n  closedir(dir);\n}\n/**\n * @param entry The command entry to remove from history\n *\n * Remove command from history.\n */\nstatic void delete_entry_history(const DRunModeEntry *entry) {\n  char *path = g_build_filename(cache_dir, DRUN_CACHE_FILE, NULL);\n  history_remove(path, entry->desktop_id);\n  g_free(path);\n}\n\nstatic void get_apps_history(DRunModePrivateData *pd) {\n  TICK_N(\"Start drun history\");\n  unsigned int length = 0;\n  gchar *path = g_build_filename(cache_dir, DRUN_CACHE_FILE, NULL);\n  gchar **retv = history_get_list(path, &length);\n  for (unsigned int index = 0; index < length; index++) {\n    for (size_t i = 0; i < pd->cmd_list_length; i++) {\n      if (g_strcmp0(pd->entry_list[i].desktop_id, retv[index]) == 0) {\n        unsigned int sort_index = length - index;\n        if (G_LIKELY(sort_index < INT_MAX)) {\n          pd->entry_list[i].sort_index = sort_index;\n        } else {\n          // This won't sort right anymore, but never gonna hit it anyway.\n          pd->entry_list[i].sort_index = INT_MAX;\n        }\n      }\n    }\n  }\n  g_strfreev(retv);\n  g_free(path);\n  TICK_N(\"Stop drun history\");\n}\n\nstatic gint drun_int_sort_list(gconstpointer a, gconstpointer b,\n                               G_GNUC_UNUSED gpointer user_data) {\n  DRunModeEntry *da = (DRunModeEntry *)a;\n  DRunModeEntry *db = (DRunModeEntry *)b;\n\n  if (da->sort_index < 0 && db->sort_index < 0) {\n    if (da->name == NULL && db->name == NULL) {\n      return 0;\n    }\n    if (da->name == NULL) {\n      return -1;\n    }\n    if (db->name == NULL) {\n      return 1;\n    }\n    return g_utf8_collate(da->name, db->name);\n  }\n  return db->sort_index - da->sort_index;\n}\n\n/*******************************************\n * Cache voodoo                            *\n *******************************************/\n\n/** Version of the DRUN cache file format. */\n#define CACHE_VERSION 3\nstatic void drun_write_str(FILE *fd, const char *str) {\n  size_t l = (str == NULL ? 0 : strlen(str));\n  fwrite(&l, sizeof(l), 1, fd);\n  // Only write string if it is not NULL or empty.\n  if (l > 0) {\n    // Also writeout terminating '\\0'\n    fwrite(str, 1, l + 1, fd);\n  }\n}\nstatic void drun_write_integer(FILE *fd, int32_t val) {\n  fwrite(&val, sizeof(val), 1, fd);\n}\nstatic gboolean drun_read_integer(FILE *fd, int32_t *type) {\n  if (fread(type, sizeof(int32_t), 1, fd) != 1) {\n    g_warning(\"Failed to read entry, cache corrupt?\");\n    return TRUE;\n  }\n  return FALSE;\n}\nstatic gboolean drun_read_string(FILE *fd, char **str) {\n  size_t l = 0;\n\n  if (fread(&l, sizeof(l), 1, fd) != 1) {\n    g_warning(\"Failed to read entry, cache corrupt?\");\n    return TRUE;\n  }\n  (*str) = NULL;\n  if (l > 0) {\n    // Include \\0\n    l++;\n    if (l > DRUN_MAX_STRING_LENGTH) {\n      return TRUE;\n    }\n    (*str) = g_malloc(l);\n    if (fread((*str), 1, l, fd) != l) {\n      g_warning(\"Failed to read entry, cache corrupt?\");\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\nstatic void drun_write_strv(FILE *fd, char **str) {\n  guint vl = (str == NULL ? 0 : g_strv_length(str));\n  fwrite(&vl, sizeof(vl), 1, fd);\n  for (guint index = 0; index < vl; index++) {\n    drun_write_str(fd, str[index]);\n  }\n}\nstatic gboolean drun_read_stringv(FILE *fd, char ***str) {\n  guint vl = 0;\n  (*str) = NULL;\n  if (fread(&vl, sizeof(vl), 1, fd) != 1) {\n    g_warning(\"Failed to read entry, cache corrupt?\");\n    return TRUE;\n  }\n  if (vl == 0) {\n    return FALSE;\n  }\n  size_t ss = sizeof(char **) * (vl + 1);\n  if (ss >= (sizeof(char **) * (UINT16_MAX))) {\n    g_warning(\"Array of string vector is to long: %u\", vl);\n    return FALSE;\n  }\n  // Include terminating NULL entry.\n  (*str) = g_malloc0(ss);\n  for (guint index = 0; index < vl; index++) {\n    if (drun_read_string(fd, &((*str)[index]))) {\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n\nstatic void write_cache(DRunModePrivateData *pd, const char *cache_file) {\n  if (cache_file == NULL || config.drun_use_desktop_cache == FALSE) {\n    return;\n  }\n  TICK_N(\"DRUN Write CACHE: start\");\n\n  FILE *fd = fopen(cache_file, \"w\");\n  if (fd == NULL) {\n    g_warning(\"Failed to write to cache file\");\n    return;\n  }\n  uint8_t version = CACHE_VERSION;\n  fwrite(&version, sizeof(version), 1, fd);\n\n  fwrite(&(pd->cmd_list_length), sizeof(pd->cmd_list_length), 1, fd);\n  for (unsigned int index = 0; index < pd->cmd_list_length; index++) {\n    DRunModeEntry *entry = &(pd->entry_list[index]);\n\n    drun_write_str(fd, entry->action);\n    drun_write_str(fd, entry->root);\n    drun_write_str(fd, entry->path);\n    drun_write_str(fd, entry->app_id);\n    drun_write_str(fd, entry->desktop_id);\n    drun_write_str(fd, entry->icon_name);\n    drun_write_str(fd, entry->exec);\n    drun_write_str(fd, entry->name);\n    drun_write_str(fd, entry->generic_name);\n\n    drun_write_strv(fd, entry->categories);\n    drun_write_strv(fd, entry->keywords);\n\n    drun_write_str(fd, entry->comment);\n    drun_write_str(fd, entry->url);\n    drun_write_integer(fd, (int32_t)entry->type);\n  }\n\n  fclose(fd);\n  TICK_N(\"DRUN Write CACHE: end\");\n}\n\n/**\n * Read cache file. returns FALSE when success.\n */\nstatic gboolean drun_read_cache(DRunModePrivateData *pd,\n                                const char *cache_file) {\n  if (cache_file == NULL || config.drun_use_desktop_cache == FALSE) {\n    return TRUE;\n  }\n\n  if (config.drun_reload_desktop_cache) {\n    return TRUE;\n  }\n  TICK_N(\"DRUN Read CACHE: start\");\n  FILE *fd = fopen(cache_file, \"r\");\n  if (fd == NULL) {\n    TICK_N(\"DRUN Read CACHE: stop\");\n    return TRUE;\n  }\n\n  // Read version.\n  uint8_t version = 0;\n\n  if (fread(&version, sizeof(version), 1, fd) != 1) {\n    fclose(fd);\n    g_warning(\"Cache corrupt, ignoring.\");\n    TICK_N(\"DRUN Read CACHE: stop\");\n    return TRUE;\n  }\n\n  if (version != CACHE_VERSION) {\n    fclose(fd);\n    g_warning(\"Cache file wrong version, ignoring.\");\n    TICK_N(\"DRUN Read CACHE: stop\");\n    return TRUE;\n  }\n\n  if (fread(&(pd->cmd_list_length), sizeof(pd->cmd_list_length), 1, fd) != 1) {\n    fclose(fd);\n    g_warning(\"Cache corrupt, ignoring.\");\n    TICK_N(\"DRUN Read CACHE: stop\");\n    return TRUE;\n  }\n  // set actual length to length;\n  pd->cmd_list_length_actual = pd->cmd_list_length;\n\n  // Do size check, check on size with\n  gsize newsize = sizeof(DRunModeEntry) * pd->cmd_list_length;\n  if ((DRUN_MAX_NUM_ENTRIES * sizeof(DRunModeEntry) < newsize)) {\n    fclose(fd);\n    g_warning(\"Cache has to many entries.\");\n    TICK_N(\"DRUN Read CACHE: stop\");\n    return TRUE;\n  }\n  pd->entry_list = g_malloc0(newsize);\n\n  int error = 0;\n  for (unsigned int index = 0; !error && index < pd->cmd_list_length; index++) {\n    DRunModeEntry *entry = &(pd->entry_list[index]);\n\n    if (drun_read_string(fd, &(entry->action))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->root))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->path))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->app_id))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->desktop_id))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->icon_name))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->exec))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->name))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->generic_name))) {\n      error = 1;\n      continue;\n    }\n\n    if (drun_read_stringv(fd, &(entry->categories))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_stringv(fd, &(entry->keywords))) {\n      error = 1;\n      continue;\n    }\n\n    if (drun_read_string(fd, &(entry->comment))) {\n      error = 1;\n      continue;\n    }\n    if (drun_read_string(fd, &(entry->url))) {\n      error = 1;\n      continue;\n    }\n    int32_t type = 0;\n    if (drun_read_integer(fd, &(type))) {\n      error = 1;\n      continue;\n    }\n    entry->type = type;\n  }\n\n  fclose(fd);\n  if (error) {\n    for (size_t i = 0; i < pd->cmd_list_length; i++) {\n      drun_entry_clear(&(pd->entry_list[i]));\n    }\n    g_free(pd->entry_list);\n    pd->cmd_list_length = 0;\n    pd->cmd_list_length_actual = 0;\n    return TRUE;\n  }\n  TICK_N(\"DRUN Read CACHE: stop\");\n  return FALSE;\n}\n\nstatic void get_apps(DRunModePrivateData *pd) {\n  char *cache_file = g_build_filename(cache_dir, DRUN_DESKTOP_CACHE_FILE, NULL);\n  TICK_N(\"Get Desktop apps (start)\");\n  if (drun_read_cache(pd, cache_file)) {\n    ThemeWidget *wid = rofi_config_find_widget(drun_mode.name, NULL, TRUE);\n\n    /** Load desktop entries */\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"scan-desktop\", FALSE);\n    if (p != NULL && (p->type == P_BOOLEAN && p->value.b)) {\n      const gchar *dir;\n      // First read the user directory.\n      dir = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);\n      walk_dir(pd, dir, dir, FALSE);\n      TICK_N(\"Get Desktop dir apps\");\n    }\n    /** Load user entires */\n    p = rofi_theme_find_property(wid, P_BOOLEAN, \"parse-user\", TRUE);\n    if (p == NULL || (p->type == P_BOOLEAN && p->value.b)) {\n      gchar *dir;\n      // First read the user directory.\n      dir = g_build_filename(g_get_user_data_dir(), \"applications\", NULL);\n      walk_dir(pd, dir, dir, TRUE);\n      g_free(dir);\n      TICK_N(\"Get Desktop apps (user dir)\");\n    }\n\n    /** Load application entires */\n    p = rofi_theme_find_property(wid, P_BOOLEAN, \"parse-system\", TRUE);\n    if (p == NULL || (p->type == P_BOOLEAN && p->value.b)) {\n      // Then read thee system data dirs.\n      const gchar *const *sys = g_get_system_data_dirs();\n      for (const gchar *const *iter = sys; *iter != NULL; ++iter) {\n        gboolean unique = TRUE;\n        // Stupid duplicate detection, better then walking dir.\n        for (const gchar *const *iterd = sys; iterd != iter; ++iterd) {\n          if (g_strcmp0(*iter, *iterd) == 0) {\n            unique = FALSE;\n          }\n        }\n        // Check, we seem to be getting empty string...\n        if (unique && (**iter) != '\\0') {\n          char *dir = g_build_filename(*iter, \"applications\", NULL);\n          walk_dir(pd, dir, dir, TRUE);\n          g_free(dir);\n        }\n      }\n      TICK_N(\"Get Desktop apps (system dirs)\");\n    }\n    pd->disable_dbusactivate = FALSE;\n    p = rofi_theme_find_property(wid, P_BOOLEAN, \"DBusActivatable\", TRUE);\n    if (p != NULL && (p->type == P_BOOLEAN && p->value.b == FALSE)) {\n      pd->disable_dbusactivate = TRUE;\n    }\n    get_apps_history(pd);\n\n    g_qsort_with_data(pd->entry_list, pd->cmd_list_length,\n                      sizeof(DRunModeEntry), drun_int_sort_list, NULL);\n\n    TICK_N(\"Sorting done.\");\n\n    write_cache(pd, cache_file);\n  } else {\n    g_debug(\"Read drun entries from cache.\");\n  }\n  g_free(cache_file);\n}\n\nstatic void drun_mode_parse_entry_fields(void) {\n  char *savept = NULL;\n  // Make a copy, as strtok will modify it.\n  char *switcher_str = g_strdup(config.drun_match_fields);\n  const char *const sep = \",#\";\n  // Split token on ','. This modifies switcher_str.\n  for (unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++) {\n    matching_entry_fields[i].enabled_match = FALSE;\n    matching_entry_fields[i].enabled_display = FALSE;\n  }\n  for (char *token = strtok_r(switcher_str, sep, &savept); token != NULL;\n       token = strtok_r(NULL, sep, &savept)) {\n    if (strcmp(token, \"all\") == 0) {\n      for (unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++) {\n        matching_entry_fields[i].enabled_match = TRUE;\n        matching_entry_fields[i].enabled_display = TRUE;\n      }\n      break;\n    }\n    gboolean matched = FALSE;\n    for (unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++) {\n      const char *entry_name = matching_entry_fields[i].entry_field_name;\n      if (g_ascii_strcasecmp(token, entry_name) == 0) {\n        matching_entry_fields[i].enabled_match = TRUE;\n        matching_entry_fields[i].enabled_display = TRUE;\n        matched = TRUE;\n      }\n    }\n    if (!matched) {\n      g_warning(\"Invalid entry name :%s\", token);\n    }\n  }\n  // Free string that was modified by strtok_r\n  g_free(switcher_str);\n}\n\nstatic void drun_mode_parse_display_format(void) {\n  for (int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++) {\n    if (matching_entry_fields[i].enabled_display)\n      continue;\n\n    gchar *search_term =\n        g_strdup_printf(\"{%s}\", matching_entry_fields[i].entry_field_name);\n    if (strstr(config.drun_display_format, search_term)) {\n      matching_entry_fields[i].enabled_match = TRUE;\n    }\n    g_free(search_term);\n  }\n}\n\nstatic int drun_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) != NULL) {\n    return TRUE;\n  }\n  DRunModePrivateData *pd = g_malloc0(sizeof(*pd));\n  pd->disabled_entries =\n      g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);\n  mode_set_private_data(sw, (void *)pd);\n  // current desktop\n  const char *current_desktop = g_getenv(\"XDG_CURRENT_DESKTOP\");\n  pd->current_desktop_list =\n      current_desktop ? g_strsplit(current_desktop, \":\", 0) : NULL;\n\n  if (config.drun_categories && *(config.drun_categories)) {\n    pd->show_categories = g_strsplit(config.drun_categories, \",\", 0);\n  }\n\n  if (config.drun_exclude_categories && *(config.drun_exclude_categories)) {\n    pd->exclude_categories = g_strsplit(config.drun_exclude_categories, \",\", 0);\n  }\n\n  drun_mode_parse_entry_fields();\n  drun_mode_parse_display_format();\n  get_apps(pd);\n\n  pd->completer = NULL;\n  return TRUE;\n}\nstatic void drun_entry_clear(DRunModeEntry *e) {\n  if (e == NULL) {\n    return;\n  }\n  g_free(e->root);\n  g_free(e->path);\n  g_free(e->app_id);\n  g_free(e->desktop_id);\n  if (e->icon != NULL) {\n    cairo_surface_destroy(e->icon);\n  }\n  g_free(e->icon_name);\n  g_free(e->exec);\n  g_free(e->name);\n  g_free(e->generic_name);\n  g_free(e->comment);\n  if (e->action != DRUN_GROUP_NAME) {\n    g_free(e->action);\n  }\n  g_strfreev(e->categories);\n  g_strfreev(e->keywords);\n  if (e->key_file) {\n    g_key_file_free(e->key_file);\n  }\n}\n\nstatic ModeMode drun_mode_result(Mode *sw, int mretv, char **input,\n                                 unsigned int selected_line) {\n  DRunModePrivateData *rmpd = (DRunModePrivateData *)mode_get_private_data(sw);\n  ModeMode retv = MODE_EXIT;\n\n  if (rmpd->file_complete == TRUE) {\n\n    retv = RELOAD_DIALOG;\n\n    if ((mretv & (MENU_COMPLETE))) {\n      g_free(rmpd->old_completer_input);\n      rmpd->old_completer_input = *input;\n      *input = NULL;\n      if (rmpd->selected_line < rmpd->cmd_list_length) {\n        (*input) = g_strdup(rmpd->old_input);\n      }\n      rmpd->file_complete = FALSE;\n    } else if ((mretv & MENU_CANCEL)) {\n      retv = MODE_EXIT;\n    } else {\n      char *path = NULL;\n      retv = mode_completer_result(rmpd->completer, mretv, input, selected_line,\n                                   &path);\n      if (retv == MODE_EXIT) {\n        exec_cmd_entry(rmpd, &(rmpd->entry_list[rmpd->selected_line]), path);\n      }\n      g_free(path);\n    }\n    return retv;\n  }\n  if ((mretv & MENU_OK)) {\n    switch (rmpd->entry_list[selected_line].type) {\n    case DRUN_DESKTOP_ENTRY_TYPE_SERVICE:\n    case DRUN_DESKTOP_ENTRY_TYPE_APPLICATION:\n      exec_cmd_entry(rmpd, &(rmpd->entry_list[selected_line]), NULL);\n      break;\n    case DRUN_DESKTOP_ENTRY_TYPE_LINK:\n      launch_link_entry(&(rmpd->entry_list[selected_line]));\n      break;\n    default:\n      g_assert_not_reached();\n    }\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&\n             *input[0] != '\\0') {\n    RofiHelperExecuteContext context = {.name = NULL};\n    gboolean run_in_term = ((mretv & MENU_CUSTOM_ACTION) == MENU_CUSTOM_ACTION);\n    // FIXME: We assume startup notification in terminals, not in others\n    if (!helper_execute_command(NULL, *input, run_in_term,\n                                run_in_term ? &context : NULL)) {\n      retv = RELOAD_DIALOG;\n    }\n  } else if ((mretv & MENU_ENTRY_DELETE) &&\n             selected_line < rmpd->cmd_list_length) {\n    // Positive sort index means it is in history.\n    if (rmpd->entry_list[selected_line].sort_index >= 0) {\n      delete_entry_history(&(rmpd->entry_list[selected_line]));\n      drun_entry_clear(&(rmpd->entry_list[selected_line]));\n      memmove(&(rmpd->entry_list[selected_line]),\n              &rmpd->entry_list[selected_line + 1],\n              sizeof(DRunModeEntry) *\n                  (rmpd->cmd_list_length - selected_line - 1));\n      rmpd->cmd_list_length--;\n    }\n    retv = RELOAD_DIALOG;\n  } else if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  } else if ((mretv & MENU_COMPLETE)) {\n    retv = RELOAD_DIALOG;\n    if (selected_line < rmpd->cmd_list_length) {\n      switch (rmpd->entry_list[selected_line].type) {\n      case DRUN_DESKTOP_ENTRY_TYPE_SERVICE:\n      case DRUN_DESKTOP_ENTRY_TYPE_APPLICATION: {\n        GRegex *regex = g_regex_new(\"%[fFuU]\", 0, 0, NULL);\n\n        if (g_regex_match(regex, rmpd->entry_list[selected_line].exec, 0,\n                          NULL)) {\n          rmpd->selected_line = selected_line;\n          // TODO add check if it supports passing file.\n\n          g_free(rmpd->old_input);\n          rmpd->old_input = g_strdup(*input);\n\n          if (*input)\n            g_free(*input);\n          *input = g_strdup(rmpd->old_completer_input);\n\n          const Mode *comp = rofi_get_completer();\n          if (comp) {\n            rmpd->completer = mode_create(comp);\n            mode_init(rmpd->completer);\n            rmpd->file_complete = TRUE;\n          }\n        }\n        g_regex_unref(regex);\n      }\n      default:\n        break;\n      }\n    }\n  }\n  return retv;\n}\nstatic void drun_mode_destroy(Mode *sw) {\n  DRunModePrivateData *rmpd = (DRunModePrivateData *)mode_get_private_data(sw);\n  if (rmpd != NULL) {\n    for (size_t i = 0; i < rmpd->cmd_list_length; i++) {\n      drun_entry_clear(&(rmpd->entry_list[i]));\n    }\n    g_hash_table_destroy(rmpd->disabled_entries);\n    g_free(rmpd->entry_list);\n\n    g_free(rmpd->old_completer_input);\n    g_free(rmpd->old_input);\n    if (rmpd->completer != NULL) {\n      mode_destroy(rmpd->completer);\n      g_free(rmpd->completer);\n    }\n\n    g_strfreev(rmpd->current_desktop_list);\n    g_strfreev(rmpd->show_categories);\n    g_strfreev(rmpd->exclude_categories);\n    g_free(rmpd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                int *state, G_GNUC_UNUSED GList **list,\n                                int get_entry) {\n  DRunModePrivateData *pd = (DRunModePrivateData *)mode_get_private_data(sw);\n\n  if (pd->file_complete) {\n    return pd->completer->_get_display_value(pd->completer, selected_line,\n                                             state, list, get_entry);\n  }\n  *state |= MARKUP;\n  if (!get_entry) {\n    return NULL;\n  }\n  if (pd->entry_list == NULL) {\n    // Should never get here.\n    return g_strdup(\"Failed\");\n  }\n  /* Free temp storage. */\n  DRunModeEntry *dr = &(pd->entry_list[selected_line]);\n  gchar *cats = NULL;\n  if (dr->categories) {\n    char *tcats = g_strjoinv(\",\", dr->categories);\n    if (tcats) {\n      cats = g_markup_escape_text(tcats, -1);\n      g_free(tcats);\n    }\n  }\n  gchar *keywords = NULL;\n  if (dr->keywords) {\n    char *tkeyw = g_strjoinv(\",\", dr->keywords);\n    if (tkeyw) {\n      keywords = g_markup_escape_text(tkeyw, -1);\n      g_free(tkeyw);\n    }\n  }\n  // Needed for display.\n  char *egn = NULL;\n  char *en = NULL;\n  char *ec = NULL;\n  char *ee = NULL;\n  char *eu = NULL;\n  if (dr->generic_name) {\n    egn = g_markup_escape_text(dr->generic_name, -1);\n  }\n  if (dr->name) {\n    en = g_markup_escape_text(dr->name, -1);\n  }\n  if (dr->comment) {\n    ec = g_markup_escape_text(dr->comment, -1);\n  }\n  if (dr->url) {\n    eu = g_markup_escape_text(dr->url, -1);\n  }\n  if (dr->exec) {\n    ee = g_markup_escape_text(dr->exec, -1);\n  }\n\n  char *retv = helper_string_replace_if_exists(\n      config.drun_display_format, \"{generic}\", egn, \"{name}\", en, \"{comment}\",\n      ec, \"{exec}\", ee, \"{categories}\", cats, \"{keywords}\", keywords, \"{url}\",\n      eu, (char *)0);\n  g_free(egn);\n  g_free(en);\n  g_free(ec);\n  g_free(eu);\n  g_free(ee);\n  g_free(cats);\n  g_free(keywords);\n  return retv;\n}\n\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int height) {\n  DRunModePrivateData *pd = (DRunModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n  if (pd->file_complete) {\n    return pd->completer->_get_icon(pd->completer, selected_line, height);\n  }\n  g_return_val_if_fail(pd->entry_list != NULL, NULL);\n  DRunModeEntry *dr = &(pd->entry_list[selected_line]);\n  if (dr->icon_name != NULL) {\n    if (dr->icon_fetch_uid > 0 && dr->icon_fetch_size == height &&\n        dr->icon_fetch_scale == scale) {\n      cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);\n      return icon;\n    }\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->icon_name, height);\n    dr->icon_fetch_size = height;\n    dr->icon_fetch_scale = scale;\n    cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);\n    return icon;\n  }\n  return NULL;\n}\n\nstatic char *drun_get_completion(const Mode *sw, unsigned int index) {\n  DRunModePrivateData *pd = (DRunModePrivateData *)mode_get_private_data(sw);\n  /* Free temp storage. */\n  DRunModeEntry *dr = &(pd->entry_list[index]);\n  if (dr->generic_name == NULL) {\n    return g_strdup(dr->name);\n  }\n  return g_strdup_printf(\"%s\", dr->name);\n}\n\nstatic int drun_token_match(const Mode *data, rofi_int_matcher **tokens,\n                            unsigned int index) {\n  DRunModePrivateData *rmpd =\n      (DRunModePrivateData *)mode_get_private_data(data);\n  if (rmpd->file_complete) {\n    return rmpd->completer->_token_match(rmpd->completer, tokens, index);\n  }\n  int match = 1;\n  if (tokens) {\n    for (int j = 0; match && tokens[j] != NULL; j++) {\n      int test = 0;\n      rofi_int_matcher *ftokens[2] = {tokens[j], NULL};\n      // Match name\n      if (matching_entry_fields[DRUN_MATCH_FIELD_NAME].enabled_match) {\n        if (rmpd->entry_list[index].name) {\n          test = helper_token_match(ftokens, rmpd->entry_list[index].name);\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_GENERIC].enabled_match) {\n        // Match generic name\n        if (test == tokens[j]->invert && rmpd->entry_list[index].generic_name) {\n          test =\n              helper_token_match(ftokens, rmpd->entry_list[index].generic_name);\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_EXEC].enabled_match) {\n        // Match executable name.\n        if (test == tokens[j]->invert && rmpd->entry_list[index].exec) {\n          test = helper_token_match(ftokens, rmpd->entry_list[index].exec);\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled_match) {\n        // Match against category.\n        if (test == tokens[j]->invert) {\n          gchar **list = rmpd->entry_list[index].categories;\n          for (int iter = 0; test == tokens[j]->invert && list && list[iter];\n               iter++) {\n            test = helper_token_match(ftokens, list[iter]);\n          }\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_KEYWORDS].enabled_match) {\n        // Match against category.\n        if (test == tokens[j]->invert) {\n          gchar **list = rmpd->entry_list[index].keywords;\n          for (int iter = 0; test == tokens[j]->invert && list && list[iter];\n               iter++) {\n            test = helper_token_match(ftokens, list[iter]);\n          }\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_URL].enabled_match) {\n\n        // Match executable name.\n        if (test == tokens[j]->invert && rmpd->entry_list[index].url) {\n          test = helper_token_match(ftokens, rmpd->entry_list[index].url);\n        }\n      }\n      if (matching_entry_fields[DRUN_MATCH_FIELD_COMMENT].enabled_match) {\n\n        // Match executable name.\n        if (test == tokens[j]->invert && rmpd->entry_list[index].comment) {\n          test = helper_token_match(ftokens, rmpd->entry_list[index].comment);\n        }\n      }\n      if (test == 0) {\n        match = 0;\n      }\n    }\n  }\n\n  return match;\n}\n\nstatic unsigned int drun_mode_get_num_entries(const Mode *sw) {\n  const DRunModePrivateData *pd =\n      (const DRunModePrivateData *)mode_get_private_data(sw);\n  if (pd->file_complete) {\n    return pd->completer->_get_num_entries(pd->completer);\n  }\n  return pd->cmd_list_length;\n}\nstatic char *drun_get_message(const Mode *sw) {\n  DRunModePrivateData *pd = sw->private_data;\n  if (pd->file_complete) {\n    if (pd->selected_line < pd->cmd_list_length) {\n      char *msg = mode_get_message(pd->completer);\n      if (msg) {\n        char *retv =\n            g_strdup_printf(\"File complete for: %s\\n%s\",\n                            pd->entry_list[pd->selected_line].name, msg);\n        g_free(msg);\n        return retv;\n      }\n      return g_strdup_printf(\"File complete for: %s\",\n                             pd->entry_list[pd->selected_line].name);\n    }\n  }\n  return NULL;\n}\n#include \"mode-private.h\"\n/** The DRun Mode interface. */\nMode drun_mode = {.name = \"drun\",\n                  .cfg_name_key = \"display-drun\",\n                  ._init = drun_mode_init,\n                  ._get_num_entries = drun_mode_get_num_entries,\n                  ._result = drun_mode_result,\n                  ._destroy = drun_mode_destroy,\n                  ._token_match = drun_token_match,\n                  ._get_message = drun_get_message,\n                  ._get_completion = drun_get_completion,\n                  ._get_display_value = _get_display_value,\n                  ._get_icon = _get_icon,\n                  ._preprocess_input = NULL,\n                  .private_data = NULL,\n                  .free = NULL,\n                  .type = MODE_TYPE_SWITCHER};\n\n#endif // ENABLE_DRUN\n"
  },
  {
    "path": "source/modes/filebrowser.c",
    "content": "/**\n * rofi-file_browser\n *\n * MIT/X11 License\n * Copyright (c) 2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include \"config.h\"\n#include <errno.h>\n#include <gio/gio.h>\n#include <gmodule.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include <dirent.h>\n#include <glib/gstdio.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"history.h\"\n#include \"mode-private.h\"\n#include \"mode.h\"\n#include \"modes/filebrowser.h\"\n#include \"rofi.h\"\n#include \"theme.h\"\n\n#include <stdint.h>\n\n#include \"rofi-icon-fetcher.h\"\n\n#define FILEBROWSER_CACHE_FILE \"rofi3.filebrowsercache\"\n/** The default program used to open the file. */\n#define DEFAULT_OPEN \"xdg-open\"\n\n#if defined(__APPLE__)\n#define st_atim st_atimespec\n#define st_ctim st_ctimespec\n#define st_mtim st_mtimespec\n#endif\n\n/**\n * The internal data structure holding the private data of the TEST Mode.\n */\nenum FBFileType {\n  UP,\n  DIRECTORY,\n  RFILE,\n  NUM_FILE_TYPES,\n};\n\n/**\n * Possible sorting methods\n */\nenum FBSortingMethod {\n  FB_SORT_NAME,\n  FB_SORT_TIME,\n};\n\n/**\n * Type of time to sort by\n */\nenum FBSortingTime {\n  FB_MTIME,\n  FB_ATIME,\n  FB_CTIME,\n};\n\n/** Icons to use for the file type */\nconst char *icon_name[NUM_FILE_TYPES] = {\"go-up\", \"folder\", \"gtk-file\"};\ntypedef struct {\n  char *name;\n  char *path;\n  enum FBFileType type;\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  gboolean link;\n  /** {time,collate_key} only valid for FB_SORT_{TIME,NAME} respectively */\n  time_t time;\n  char *collate_key;\n} FBFile;\n\ntypedef struct {\n  char *command;\n  GFile *current_dir;\n  FBFile *array;\n  unsigned int array_length;\n  unsigned int array_length_real;\n} FileBrowserModePrivateData;\n\n/**\n * The sorting settings used in file-browser.\n */\nstruct {\n  /** Field to sort on. */\n  enum FBSortingMethod sorting_method;\n  /** If sorting on time, what time entry. */\n  enum FBSortingTime sorting_time;\n  /** If we want to display directories above files. */\n  gboolean directories_first;\n  /** If we want to show hidden files. */\n  gboolean show_hidden;\n} file_browser_config = {\n    .sorting_method = FB_SORT_NAME,\n    .sorting_time = FB_MTIME,\n    .directories_first = TRUE,\n    .show_hidden = FALSE,\n};\n\nstatic void free_list(FileBrowserModePrivateData *pd) {\n  for (unsigned int i = 0; i < pd->array_length; i++) {\n    FBFile *fb = &(pd->array[i]);\n    g_free(fb->name);\n    g_free(fb->path);\n    g_free(fb->collate_key);\n  }\n  g_free(pd->array);\n  pd->array = NULL;\n  pd->array_length = 0;\n  pd->array_length_real = 0;\n}\n#include <dirent.h>\n#include <sys/types.h>\n\nstatic gint compare_name(gconstpointer a, gconstpointer b,\n                         G_GNUC_UNUSED gpointer data) {\n  FBFile *fa = (FBFile *)a;\n  FBFile *fb = (FBFile *)b;\n\n  if (file_browser_config.directories_first && fa->type != fb->type) {\n    return fa->type - fb->type;\n  }\n\n  return g_strcmp0(fa->collate_key, fb->collate_key);\n}\n\nstatic gint compare_time(gconstpointer a, gconstpointer b,\n                         G_GNUC_UNUSED gpointer data) {\n  FBFile *fa = (FBFile *)a;\n  FBFile *fb = (FBFile *)b;\n\n  if (file_browser_config.directories_first && fa->type != fb->type) {\n    return fa->type - fb->type;\n  }\n\n  if (fa->time < 0) {\n    return -1;\n  }\n\n  if (fb->time < 0) {\n    return 1;\n  }\n\n  return fb->time - fa->time;\n}\n\nstatic gint compare(gconstpointer a, gconstpointer b, gpointer data) {\n  GCompareDataFunc comparator = NULL;\n\n  switch (file_browser_config.sorting_method) {\n  case FB_SORT_NAME:\n    comparator = compare_name;\n    break;\n  case FB_SORT_TIME:\n    comparator = compare_time;\n    break;\n  default:\n    comparator = compare_name;\n    break;\n  }\n\n  return comparator(a, b, data);\n}\n\nstatic time_t get_time(const GStatBuf *statbuf) {\n  switch (file_browser_config.sorting_time) {\n  case FB_MTIME:\n    return statbuf->st_mtim.tv_sec;\n  case FB_ATIME:\n    return statbuf->st_atim.tv_sec;\n  case FB_CTIME:\n    return statbuf->st_ctim.tv_sec;\n  default:\n    return 0;\n  }\n}\n\nstatic void set_time(FBFile *file) {\n  // GError *error = NULL;\n  //  gchar *path = g_filename_from_utf8(file->path, -1, NULL, NULL, &error);\n  //  if (error) {\n  //    g_warning(\"Failed to convert filename: %s: %s\", file->path,\n  //    error->message); g_error_free(error); return;\n  //  }\n\n  GStatBuf statbuf;\n\n  if (g_lstat(file->path, &statbuf) == 0) {\n    file->time = get_time(&statbuf);\n  } else {\n    g_warning(\"Failed to stat file: %s, %s\", file->path, strerror(errno));\n  }\n\n  //  g_free(path);\n}\n\nstatic void set_collate_key(FBFile *file) {\n  file->collate_key = g_utf8_collate_key_for_filename(file->name, -1);\n}\n\ninline static void fb_resize_array(FileBrowserModePrivateData *pd) {\n  if ((pd->array_length + 1) > pd->array_length_real) {\n    pd->array_length_real += 256;\n    pd->array =\n        g_realloc(pd->array, (pd->array_length_real + 1) * sizeof(FBFile));\n  }\n}\n\nstatic void get_file_browser(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  /**\n   * Get the entries to display.\n   * this gets called on plugin initialization.\n   */\n  char *cdir = g_file_get_path(pd->current_dir);\n  DIR *dir = opendir(cdir);\n  if (dir) {\n    struct dirent *rd = NULL;\n    while ((rd = readdir(dir)) != NULL) {\n      if (g_strcmp0(rd->d_name, \"..\") == 0) {\n        fb_resize_array(pd);\n        // Rofi expects utf-8, so lets convert the filename.\n        pd->array[pd->array_length].name = g_strdup(\"..\");\n        pd->array[pd->array_length].path = NULL;\n        pd->array[pd->array_length].type = UP;\n        pd->array[pd->array_length].icon_fetch_uid = 0;\n        pd->array[pd->array_length].icon_fetch_size = 0;\n        pd->array[pd->array_length].icon_fetch_scale = 0;\n        pd->array[pd->array_length].link = FALSE;\n        pd->array[pd->array_length].time = -1;\n        pd->array[pd->array_length].collate_key = NULL;\n        pd->array_length++;\n        continue;\n      }\n      if (g_strcmp0(rd->d_name, \".\") == 0) {\n        continue;\n      }\n      if (rd->d_name[0] == '.' && file_browser_config.show_hidden == FALSE) {\n        continue;\n      }\n\n      switch (rd->d_type) {\n      case DT_BLK:\n      case DT_CHR:\n      case DT_FIFO:\n      case DT_UNKNOWN:\n      case DT_SOCK:\n      default:\n        break;\n      case DT_REG:\n      case DT_DIR:\n        fb_resize_array(pd);\n        // Rofi expects utf-8, so lets convert the filename.\n        pd->array[pd->array_length].name =\n            g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);\n        if (pd->array[pd->array_length].name == NULL) {\n          pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);\n        }\n        pd->array[pd->array_length].path =\n            g_build_filename(cdir, rd->d_name, NULL);\n        pd->array[pd->array_length].type =\n            (rd->d_type == DT_DIR) ? DIRECTORY : RFILE;\n        pd->array[pd->array_length].icon_fetch_uid = 0;\n        pd->array[pd->array_length].icon_fetch_size = 0;\n        pd->array[pd->array_length].icon_fetch_scale = 0;\n        pd->array[pd->array_length].link = FALSE;\n\n        if (file_browser_config.sorting_method == FB_SORT_NAME) {\n          set_collate_key(&pd->array[pd->array_length]);\n        } else if (file_browser_config.sorting_method == FB_SORT_TIME) {\n          set_time(&pd->array[pd->array_length]);\n        }\n\n        pd->array_length++;\n        break;\n      case DT_LNK:\n        fb_resize_array(pd);\n        // Rofi expects utf-8, so lets convert the filename.\n        pd->array[pd->array_length].name =\n            g_filename_to_utf8(rd->d_name, -1, NULL, NULL, NULL);\n        if (pd->array[pd->array_length].name == NULL) {\n          pd->array[pd->array_length].name = rofi_force_utf8(rd->d_name, -1);\n        }\n        pd->array[pd->array_length].path =\n            g_build_filename(cdir, rd->d_name, NULL);\n        pd->array[pd->array_length].icon_fetch_uid = 0;\n        pd->array[pd->array_length].icon_fetch_size = 0;\n        pd->array[pd->array_length].icon_fetch_scale = 0;\n        pd->array[pd->array_length].link = TRUE;\n        // Default to file.\n        pd->array[pd->array_length].type = RFILE;\n\n        if (file_browser_config.sorting_method == FB_SORT_NAME) {\n          set_collate_key(&pd->array[pd->array_length]);\n        }\n\n        {\n          // If we have link, use a stat to fine out what it is, if we fail, we\n          // mark it as file.\n          // TODO have a 'broken link' mode?\n          // Convert full path to right encoding.\n          // DD: Path should be in file encoding, not utf-8\n          //          char *file =\n          //          g_filename_from_utf8(pd->array[pd->array_length].path,\n          //                                            -1, NULL, NULL, NULL);\n          if (pd->array[pd->array_length].path) {\n            GStatBuf statbuf;\n            if (g_stat(pd->array[pd->array_length].path, &statbuf) == 0) {\n              if (S_ISDIR(statbuf.st_mode)) {\n                pd->array[pd->array_length].type = DIRECTORY;\n              } else if (S_ISREG(statbuf.st_mode)) {\n                pd->array[pd->array_length].type = RFILE;\n              }\n\n              if (file_browser_config.sorting_method == FB_SORT_TIME) {\n                pd->array[pd->array_length].time = get_time(&statbuf);\n              }\n            } else {\n              g_warning(\"Failed to stat file: %s, %s\",\n                        pd->array[pd->array_length].path, strerror(errno));\n            }\n\n            //            g_free(file);\n          }\n        }\n        pd->array_length++;\n        break;\n      }\n    }\n    closedir(dir);\n  }\n  g_free(cdir);\n  g_qsort_with_data(pd->array, pd->array_length, sizeof(FBFile), compare, NULL);\n}\n\nstatic void file_browser_mode_init_config(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  char *msg = NULL;\n  gboolean found_error = FALSE;\n\n  ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n\n  Property *p = rofi_theme_find_property(wid, P_STRING, \"sorting-method\", TRUE);\n  if (p != NULL && p->type == P_STRING) {\n    if (g_strcmp0(p->value.s, \"name\") == 0) {\n      file_browser_config.sorting_method = FB_SORT_NAME;\n    } else if (g_strcmp0(p->value.s, \"mtime\") == 0) {\n      file_browser_config.sorting_method = FB_SORT_TIME;\n      file_browser_config.sorting_time = FB_MTIME;\n    } else if (g_strcmp0(p->value.s, \"atime\") == 0) {\n      file_browser_config.sorting_method = FB_SORT_TIME;\n      file_browser_config.sorting_time = FB_ATIME;\n    } else if (g_strcmp0(p->value.s, \"ctime\") == 0) {\n      file_browser_config.sorting_method = FB_SORT_TIME;\n      file_browser_config.sorting_time = FB_CTIME;\n    } else {\n      found_error = TRUE;\n\n      msg = g_strdup_printf(\"\\\"%s\\\" is not a valid filebrowser sorting method\",\n                            p->value.s);\n    }\n  }\n\n  p = rofi_theme_find_property(wid, P_BOOLEAN, \"directories-first\", TRUE);\n  if (p != NULL && p->type == P_BOOLEAN) {\n    file_browser_config.directories_first = p->value.b;\n  }\n\n  p = rofi_theme_find_property(wid, P_BOOLEAN, \"show-hidden\", TRUE);\n  if (p != NULL && p->type == P_BOOLEAN) {\n    file_browser_config.show_hidden = p->value.b;\n  }\n\n  p = rofi_theme_find_property(wid, P_STRING, \"command\", TRUE);\n  if (p != NULL && p->type == P_STRING) {\n    pd->command = g_strdup(p->value.s);\n  } else {\n    pd->command = g_strdup(DEFAULT_OPEN);\n  }\n\n  if (found_error) {\n    rofi_view_error_dialog(msg, FALSE);\n\n    g_free(msg);\n  }\n}\n\nstatic void file_browser_mode_init_current_dir(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n\n  Property *p = rofi_theme_find_property(wid, P_STRING, \"directory\", TRUE);\n\n  gboolean config_has_valid_dir = p != NULL && p->type == P_STRING &&\n                                  g_file_test(p->value.s, G_FILE_TEST_IS_DIR);\n\n  if (config_has_valid_dir) {\n    pd->current_dir = g_file_new_for_path(p->value.s);\n  } else {\n    char *current_dir = NULL;\n    char *cache_file =\n        g_build_filename(cache_dir, FILEBROWSER_CACHE_FILE, NULL);\n\n    if (g_file_get_contents(cache_file, &current_dir, NULL, NULL)) {\n      if (g_file_test(current_dir, G_FILE_TEST_IS_DIR)) {\n        pd->current_dir = g_file_new_for_path(current_dir);\n      }\n\n      g_free(current_dir);\n    }\n\n    // Store it based on the unique identifiers (desktop_id).\n    g_free(cache_file);\n  }\n\n  if (pd->current_dir == NULL) {\n    pd->current_dir = g_file_new_for_path(g_get_home_dir());\n  }\n}\n\nstatic int file_browser_mode_init(Mode *sw) {\n  /**\n   * Called on startup when enabled (in modes list)\n   */\n  if (mode_get_private_data(sw) == NULL) {\n    FileBrowserModePrivateData *pd = g_malloc0(sizeof(*pd));\n    mode_set_private_data(sw, (void *)pd);\n\n    file_browser_mode_init_config(sw);\n    file_browser_mode_init_current_dir(sw);\n\n    // Load content.\n    get_file_browser(sw);\n  }\n  return TRUE;\n}\nstatic unsigned int file_browser_mode_get_num_entries(const Mode *sw) {\n  const FileBrowserModePrivateData *pd =\n      (const FileBrowserModePrivateData *)mode_get_private_data(sw);\n  return pd->array_length;\n}\n\nstatic ModeMode file_browser_mode_result(Mode *sw, int mretv, char **input,\n                                         unsigned int selected_line) {\n  ModeMode retv = MODE_EXIT;\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  if ((mretv & MENU_CANCEL) == MENU_CANCEL) {\n    ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"cancel-returns-1\", TRUE);\n    if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n      rofi_set_return_code(1);\n    }\n    return MODE_EXIT;\n  }\n  gboolean special_command =\n      ((mretv & MENU_CUSTOM_ACTION) == MENU_CUSTOM_ACTION);\n  if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  } else if ((mretv & MENU_OK)) {\n    if (selected_line < pd->array_length) {\n      if (pd->array[selected_line].type == UP) {\n        GFile *new = g_file_get_parent(pd->current_dir);\n        if (new) {\n          g_object_unref(pd->current_dir);\n          pd->current_dir = new;\n          free_list(pd);\n          get_file_browser(sw);\n          return RESET_DIALOG;\n        }\n      } else if ((pd->array[selected_line].type == RFILE) ||\n                 (pd->array[selected_line].type == DIRECTORY &&\n                  special_command)) {\n        char *d_esc = g_shell_quote(pd->array[selected_line].path);\n        char *cmd = g_strdup_printf(\"%s %s\", pd->command, d_esc);\n        g_free(d_esc);\n        char *cdir = g_file_get_path(pd->current_dir);\n        helper_execute_command(cdir, cmd, FALSE, NULL);\n        g_free(cdir);\n        g_free(cmd);\n        return MODE_EXIT;\n      } else if (pd->array[selected_line].type == DIRECTORY) {\n        char *path = g_build_filename(cache_dir, FILEBROWSER_CACHE_FILE, NULL);\n        g_file_set_contents(path, pd->array[selected_line].path, -1, NULL);\n        g_free(path);\n        GFile *new = g_file_new_for_path(pd->array[selected_line].path);\n        g_object_unref(pd->current_dir);\n        pd->current_dir = new;\n        free_list(pd);\n        get_file_browser(sw);\n        return RESET_DIALOG;\n      }\n    }\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_CUSTOM_INPUT)) {\n    if (special_command) {\n      GFile *new = g_file_get_parent(pd->current_dir);\n      if (new) {\n        g_object_unref(pd->current_dir);\n        pd->current_dir = new;\n        free_list(pd);\n        get_file_browser(sw);\n      }\n      return RESET_DIALOG;\n    }\n    if (*input) {\n      char *p = rofi_expand_path(*input);\n      char *dir = g_filename_from_utf8(p, -1, NULL, NULL, NULL);\n      g_free(p);\n      if (g_file_test(dir, G_FILE_TEST_EXISTS)) {\n        if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {\n          g_object_unref(pd->current_dir);\n          pd->current_dir = g_file_new_for_path(dir);\n          g_free(dir);\n          free_list(pd);\n          get_file_browser(sw);\n          return RESET_DIALOG;\n        }\n      }\n      g_free(dir);\n      retv = RELOAD_DIALOG;\n    }\n  } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {\n    file_browser_config.show_hidden = !file_browser_config.show_hidden;\n    free_list(pd);\n    get_file_browser(sw);\n    retv = RELOAD_DIALOG;\n  }\n  return retv;\n}\n\nstatic void file_browser_mode_destroy(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if (pd != NULL) {\n    g_object_unref(pd->current_dir);\n    g_free(pd->command);\n    free_list(pd);\n    g_free(pd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                G_GNUC_UNUSED int *state,\n                                G_GNUC_UNUSED GList **attr_list,\n                                int get_entry) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  // Only return the string if requested, otherwise only set state.\n  if (!get_entry) {\n    return NULL;\n  }\n  if (pd->array[selected_line].type == UP) {\n    return g_strdup(\" ..\");\n  }\n  if (pd->array[selected_line].link) {\n    return g_strconcat(\"@\", pd->array[selected_line].name, NULL);\n  }\n  return g_strdup(pd->array[selected_line].name);\n}\n\n/**\n * @param sw The mode object.\n * @param tokens The tokens to match against.\n * @param index  The index in this plugin to match against.\n *\n * Match the entry.\n *\n * @returns try when a match.\n */\nstatic int file_browser_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                                    unsigned int index) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  // Call default matching function.\n  return helper_token_match(tokens, pd->array[index].name);\n}\n\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int height) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n  g_return_val_if_fail(pd->array != NULL, NULL);\n  FBFile *dr = &(pd->array[selected_line]);\n  if (rofi_icon_fetcher_file_is_image(dr->path)) {\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->path, height);\n  } else if (dr->type == RFILE) {\n    gchar* _path = g_strconcat(\"thumbnail://\", dr->path, NULL);\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(_path, height);\n    g_free(_path);\n  } else {\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(icon_name[dr->type], height);\n  }\n  dr->icon_fetch_size = height;\n  dr->icon_fetch_scale = scale;\n  return rofi_icon_fetcher_get(dr->icon_fetch_uid);\n}\n\nstatic char *_get_message(const Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if (pd->current_dir) {\n    char *dirname = g_file_get_parse_name(pd->current_dir);\n    char *str =\n        g_markup_printf_escaped(\"<b>Current directory:</b> %s\", dirname);\n    g_free(dirname);\n    return str;\n  }\n  return \"n/a\";\n}\n\nstatic char *_get_completion(const Mode *sw, unsigned int index) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  char *d = g_strescape(pd->array[index].path, NULL);\n  return d;\n}\n\nMode *create_new_file_browser(void) {\n  Mode *sw = g_malloc0(sizeof(Mode));\n\n  *sw = file_browser_mode;\n\n  sw->private_data = NULL;\n  return sw;\n}\n\n#if 1\nModeMode file_browser_mode_completer(Mode *sw, int mretv, char **input,\n                                     unsigned int selected_line, char **path) {\n  ModeMode retv = MODE_EXIT;\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if ((mretv & MENU_OK)) {\n    if (selected_line < pd->array_length) {\n      if (pd->array[selected_line].type == UP) {\n        GFile *new = g_file_get_parent(pd->current_dir);\n        if (new) {\n          g_object_unref(pd->current_dir);\n          pd->current_dir = new;\n          free_list(pd);\n          get_file_browser(sw);\n          return RESET_DIALOG;\n        }\n      } else if (pd->array[selected_line].type == DIRECTORY) {\n        GFile *new = g_file_new_for_path(pd->array[selected_line].path);\n        g_object_unref(pd->current_dir);\n        pd->current_dir = new;\n        free_list(pd);\n        get_file_browser(sw);\n        return RESET_DIALOG;\n      } else if (pd->array[selected_line].type == RFILE) {\n        *path = g_strescape(pd->array[selected_line].path, NULL);\n        return MODE_EXIT;\n      }\n    }\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input) {\n    char *p = rofi_expand_path(*input);\n    char *dir = g_filename_from_utf8(p, -1, NULL, NULL, NULL);\n    g_free(p);\n    if (g_file_test(dir, G_FILE_TEST_EXISTS)) {\n      if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {\n        g_object_unref(pd->current_dir);\n        pd->current_dir = g_file_new_for_path(dir);\n        g_free(dir);\n        free_list(pd);\n        get_file_browser(sw);\n        return RESET_DIALOG;\n      }\n    }\n    g_free(dir);\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {\n    file_browser_config.show_hidden = !file_browser_config.show_hidden;\n    free_list(pd);\n    get_file_browser(sw);\n    retv = RELOAD_DIALOG;\n  }\n  return retv;\n}\n#endif\n\nMode file_browser_mode = {.display_name = NULL,\n                          .abi_version = ABI_VERSION,\n                          .name = \"filebrowser\",\n                          .cfg_name_key = \"display-filebrowser\",\n                          ._init = file_browser_mode_init,\n                          ._get_num_entries = file_browser_mode_get_num_entries,\n                          ._result = file_browser_mode_result,\n                          ._destroy = file_browser_mode_destroy,\n                          ._token_match = file_browser_token_match,\n                          ._get_display_value = _get_display_value,\n                          ._get_icon = _get_icon,\n                          ._get_message = _get_message,\n                          ._get_completion = _get_completion,\n                          ._preprocess_input = NULL,\n                          ._create = create_new_file_browser,\n                          ._completer_result = file_browser_mode_completer,\n                          .private_data = NULL,\n                          .free = NULL,\n                          .type = MODE_TYPE_SWITCHER | MODE_TYPE_COMPLETER};\n"
  },
  {
    "path": "source/modes/help-keys.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"config.h\"\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <dirent.h>\n#include <errno.h>\n#include <limits.h>\n#include <signal.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"helper.h\"\n#include \"modes/help-keys.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"widgets/textbox.h\"\n#include \"xrmoptions.h\"\n\ntypedef struct {\n  /** array of strings containing key descriptions */\n  char **messages;\n  /** lengths of the messages array */\n  unsigned int messages_length;\n} KeysHelpModePrivateData;\n\nstatic void get_apps(KeysHelpModePrivateData *pd) {\n  pd->messages = config_parser_return_display_help(&(pd->messages_length));\n}\n\nstatic int help_keys_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n    KeysHelpModePrivateData *pd = g_malloc0(sizeof(*pd));\n    mode_set_private_data(sw, (void *)pd);\n    get_apps(pd);\n  }\n  return TRUE;\n}\n\nstatic ModeMode\nhelp_keys_mode_result(G_GNUC_UNUSED Mode *sw, int mretv,\n                      G_GNUC_UNUSED char **input,\n                      G_GNUC_UNUSED unsigned int selected_line) {\n  if (mretv & MENU_CUSTOM_COMMAND) {\n    int retv = (mretv & MENU_LOWER_MASK);\n    return retv;\n  }\n  return MODE_EXIT;\n}\nstatic void help_keys_mode_destroy(Mode *sw) {\n  KeysHelpModePrivateData *rmpd =\n      (KeysHelpModePrivateData *)mode_get_private_data(sw);\n  if (rmpd != NULL) {\n    g_strfreev(rmpd->messages);\n    g_free(rmpd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                int *state, G_GNUC_UNUSED GList **list,\n                                int get_entry) {\n  KeysHelpModePrivateData *pd =\n      (KeysHelpModePrivateData *)mode_get_private_data(sw);\n  *state |= MARKUP;\n  if (!get_entry) {\n    return NULL;\n  }\n  return g_strdup(pd->messages[selected_line]);\n}\nstatic int help_keys_token_match(const Mode *data, rofi_int_matcher **tokens,\n                                 unsigned int index) {\n  KeysHelpModePrivateData *rmpd =\n      (KeysHelpModePrivateData *)mode_get_private_data(data);\n  return helper_token_match(tokens, rmpd->messages[index]);\n}\n\nstatic unsigned int help_keys_mode_get_num_entries(const Mode *sw) {\n  const KeysHelpModePrivateData *pd =\n      (const KeysHelpModePrivateData *)mode_get_private_data(sw);\n  return pd->messages_length;\n}\n\n#include \"mode-private.h\"\nMode help_keys_mode = {.name = \"keys\",\n                       .cfg_name_key = \"display-keys\",\n                       ._init = help_keys_mode_init,\n                       ._get_num_entries = help_keys_mode_get_num_entries,\n                       ._result = help_keys_mode_result,\n                       ._destroy = help_keys_mode_destroy,\n                       ._token_match = help_keys_token_match,\n                       ._get_completion = NULL,\n                       ._get_display_value = _get_display_value,\n                       .private_data = NULL,\n                       .free = NULL,\n                       .type = MODE_TYPE_SWITCHER};\n"
  },
  {
    "path": "source/modes/recursivebrowser.c",
    "content": "/**\n * rofi-recursive_browser\n *\n * MIT/X11 License\n * Copyright (c) 2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#define G_LOG_DOMAIN \"Modes.RecursiveBrowser\"\n\n#include \"glib.h\"\n\n#include \"config.h\"\n#include <errno.h>\n#include <gio/gio.h>\n#include <gmodule.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include <dirent.h>\n#include <glib-unix.h>\n#include <glib/gstdio.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"history.h\"\n#include \"mode-private.h\"\n#include \"mode.h\"\n#include \"modes/recursivebrowser.h\"\n#include \"rofi.h\"\n#include \"theme.h\"\n\n#include <stdint.h>\n\n#include \"rofi-icon-fetcher.h\"\n\n/** The default program used to open the file. */\n#define DEFAULT_OPEN \"xdg-open\"\n\n/**\n * The internal data structure holding the private data of the TEST Mode.\n */\nenum FBFileType {\n  UP,\n  DIRECTORY,\n  RFILE,\n  NUM_FILE_TYPES,\n};\n\n/** Icons to use for the file type */\nconst char *rb_icon_name[NUM_FILE_TYPES] = {\"go-up\", \"folder\", \"gtk-file\"};\ntypedef struct {\n  char *name;\n  char *path;\n  enum FBFileType type;\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  gboolean link;\n  time_t time;\n} FBFile;\n\ntypedef struct {\n  char *command;\n  GFile *current_dir;\n  FBFile *array;\n  unsigned int array_length;\n  unsigned int array_length_real;\n\n  GThread *reading_thread;\n  GAsyncQueue *async_queue;\n  guint wake_source;\n  guint end_thread;\n  gboolean loading;\n  int pipefd2[2];\n  GRegex *filter_regex;\n} FileBrowserModePrivateData;\n\nstatic void free_list(FileBrowserModePrivateData *pd) {\n  for (unsigned int i = 0; i < pd->array_length; i++) {\n    FBFile *fb = &(pd->array[i]);\n    g_free(fb->name);\n    g_free(fb->path);\n  }\n  g_free(pd->array);\n  pd->array = NULL;\n  pd->array_length = 0;\n  pd->array_length_real = 0;\n}\n#include <dirent.h>\n#include <sys/types.h>\n\ninline static void fb_resize_array(FileBrowserModePrivateData *pd) {\n  if ((pd->array_length + 1) > pd->array_length_real) {\n    pd->array_length_real += 10240;\n    pd->array =\n        g_realloc(pd->array, (pd->array_length_real + 1) * sizeof(FBFile));\n  }\n}\n\nstatic void recursive_browser_mode_init_config(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  char *msg = NULL;\n  gboolean found_error = FALSE;\n\n  ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n  Property *p =\n      rofi_theme_find_property(wid, P_BOOLEAN, \"cancel-returns-1\", TRUE);\n  if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n    rofi_set_return_code(1);\n  }\n\n  p = rofi_theme_find_property(wid, P_STRING, \"filter-regex\", TRUE);\n  if (p != NULL && p->type == P_STRING) {\n    GError *error = NULL;\n    g_debug(\"compile regex: %s\\n\", p->value.s);\n    pd->filter_regex = g_regex_new(p->value.s, G_REGEX_OPTIMIZE, 0, &error);\n    if (error) {\n      msg = g_strdup_printf(\"\\\"%s\\\" is not a valid regex for filtering: %s\",\n                            p->value.s, error->message);\n      found_error = TRUE;\n      g_error_free(error);\n    }\n  }\n  if (pd->filter_regex == NULL) {\n    g_debug(\"compile default regex\\n\");\n    pd->filter_regex = g_regex_new(\"^(\\\\..*)\", G_REGEX_OPTIMIZE, 0, NULL);\n  }\n  p = rofi_theme_find_property(wid, P_STRING, \"command\", TRUE);\n  if (p != NULL && p->type == P_STRING) {\n    pd->command = g_strdup(p->value.s);\n  } else {\n    pd->command = g_strdup(DEFAULT_OPEN);\n  }\n\n  if (found_error) {\n    rofi_view_error_dialog(msg, FALSE);\n\n    g_free(msg);\n  }\n}\n\nstatic void recursive_browser_mode_init_current_dir(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n\n  Property *p = rofi_theme_find_property(wid, P_STRING, \"directory\", TRUE);\n\n  gboolean config_has_valid_dir = p != NULL && p->type == P_STRING &&\n                                  g_file_test(p->value.s, G_FILE_TEST_IS_DIR);\n\n  if (config_has_valid_dir) {\n    pd->current_dir = g_file_new_for_path(p->value.s);\n  }\n  if (pd->current_dir == NULL) {\n    pd->current_dir = g_file_new_for_path(g_get_home_dir());\n  }\n}\n\nstatic void scan_dir(FileBrowserModePrivateData *pd, GFile *path) {\n  GQueue *dirs_to_scan = g_queue_new();\n  GHashTable *dirs_scanned =\n      g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL);\n  g_queue_push_tail(dirs_to_scan, g_object_ref(path));\n  GFile *dir_to_scan = NULL;\n  while ((dir_to_scan = g_queue_pop_head(dirs_to_scan)) != NULL) {\n    char *cdir = g_file_get_path(dir_to_scan);\n    // Check if we already visited this directory.\n    if (g_hash_table_lookup_extended(dirs_scanned, cdir, NULL, NULL)) {\n      g_free(cdir);\n      continue;\n    }\n    g_hash_table_insert(dirs_scanned, g_strdup(cdir), NULL);\n    DIR *dir = opendir(cdir);\n    g_object_unref(dir_to_scan);\n    if (dir) {\n      struct dirent *rd = NULL;\n      while (pd->end_thread == FALSE && (rd = readdir(dir)) != NULL) {\n        if (g_strcmp0(rd->d_name, \"..\") == 0) {\n          continue;\n        }\n        if (g_strcmp0(rd->d_name, \".\") == 0) {\n          continue;\n        }\n        if (pd->filter_regex &&\n            g_regex_match(pd->filter_regex, rd->d_name, 0, NULL)) {\n          continue;\n        }\n        switch (rd->d_type) {\n        case DT_BLK:\n        case DT_CHR:\n        case DT_FIFO:\n        case DT_SOCK:\n        default:\n          break;\n        case DT_REG: {\n          FBFile *f = g_malloc0(sizeof(FBFile));\n          // Rofi expects utf-8, so lets convert the filename.\n          f->path = g_build_filename(cdir, rd->d_name, NULL);\n          f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL);\n          if (f->name == NULL) {\n            f->name = rofi_force_utf8(rd->d_name, -1);\n          }\n          if (f->name == NULL) {\n            f->name = g_strdup(\"n/a\");\n          }\n          f->type = (rd->d_type == DT_DIR) ? DIRECTORY : RFILE;\n          f->icon_fetch_uid = 0;\n          f->icon_fetch_size = 0;\n          f->icon_fetch_scale = 0;\n          f->link = FALSE;\n\n          g_async_queue_push(pd->async_queue, f);\n          if (g_async_queue_length(pd->async_queue) > 10000) {\n            write(pd->pipefd2[1], \"r\", 1);\n          }\n          break;\n        }\n        case DT_DIR: {\n          char *d = g_build_filename(cdir, rd->d_name, NULL);\n          GFile *dirp = g_file_new_for_path(d);\n          g_queue_push_tail(dirs_to_scan, dirp);\n          g_free(d);\n          break;\n        }\n        case DT_UNKNOWN:\n        case DT_LNK: {\n          FBFile *f = g_malloc0(sizeof(FBFile));\n          // Rofi expects utf-8, so lets convert the filename.\n          f->path = g_build_filename(cdir, rd->d_name, NULL);\n          f->name = g_filename_to_utf8(f->path, -1, NULL, NULL, NULL);\n          if (f->name == NULL) {\n            f->name = rofi_force_utf8(rd->d_name, -1);\n          }\n          if (f->name == NULL) {\n            f->name = g_strdup(\"n/a\");\n          }\n          f->icon_fetch_uid = 0;\n          f->icon_fetch_size = 0;\n          f->icon_fetch_scale = 0;\n          // Default to file.\n          f->type = RFILE;\n          if (rd->d_type == DT_LNK) {\n            f->link = TRUE;\n          } else {\n            f->link = FALSE;\n          }\n          {\n            // If we have link, use a stat to fine out what it is, if we fail,\n            // we mark it as file.\n            // TODO have a 'broken link' mode?\n            // Convert full path to right encoding.\n            // DD: Path should be in file encoding, not utf-8\n            //          char *file =\n            //          g_filename_from_utf8(pd->array[pd->array_length].path,\n            //                                            -1, NULL, NULL, NULL);\n            // TODO: How to handle loops in links.\n            if (f->path) {\n              GStatBuf statbuf;\n              if (g_stat(f->path, &statbuf) == 0) {\n                if (S_ISDIR(statbuf.st_mode)) {\n                  char *new_full_path =\n                      g_build_filename(cdir, rd->d_name, NULL);\n                  g_free(f->path);\n                  g_free(f->name);\n                  g_free(f);\n                  f = NULL;\n                  // resolve the symlink.\n                  char *sym = g_file_read_link(new_full_path, NULL);\n                  if (sym) {\n                    GFile *dirp = g_file_new_for_path(sym);\n                    g_queue_push_tail(dirs_to_scan, dirp);\n                    g_free(sym);\n                  }\n                  g_free(new_full_path);\n                  break;\n                } else if (S_ISREG(statbuf.st_mode)) {\n                  f->type = RFILE;\n                }\n\n              } else {\n                g_warning(\"Failed to stat file: %s, %s\", f->path,\n                          strerror(errno));\n              }\n            }\n          }\n          if (f != NULL) {\n            g_async_queue_push(pd->async_queue, f);\n            if (g_async_queue_length(pd->async_queue) > 10000) {\n              write(pd->pipefd2[1], \"r\", 1);\n            }\n          }\n          break;\n        }\n        }\n      }\n      closedir(dir);\n    }\n    g_free(cdir);\n  }\n  g_hash_table_destroy(dirs_scanned);\n\n  g_queue_free(dirs_to_scan);\n}\nstatic gpointer recursive_browser_input_thread(gpointer userdata) {\n  FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)userdata;\n  GTimer *t = g_timer_new();\n  g_debug(\"Start scan.\\n\");\n  scan_dir(pd, pd->current_dir);\n  write(pd->pipefd2[1], \"r\", 1);\n  write(pd->pipefd2[1], \"q\", 1);\n  double f = g_timer_elapsed(t, NULL);\n  g_debug(\"End scan: %f\\n\", f);\n  g_timer_destroy(t);\n  return NULL;\n}\nstatic gboolean recursive_browser_async_read_proc(gint fd,\n                                                  GIOCondition condition,\n                                                  gpointer user_data) {\n  FileBrowserModePrivateData *pd = (FileBrowserModePrivateData *)user_data;\n  char command;\n  // Only interrested in read events.\n  if ((condition & G_IO_IN) != G_IO_IN) {\n    return G_SOURCE_CONTINUE;\n  }\n  // Read the entry from the pipe that was used to signal this action.\n  if (read(fd, &command, 1) == 1) {\n    if (command == 'r') {\n      FBFile *block = NULL;\n      gboolean changed = FALSE;\n      // Empty out the AsyncQueue (that is thread safe) from all blocks pushed\n      // into it.\n      while ((block = g_async_queue_try_pop(pd->async_queue)) != NULL) {\n\n        fb_resize_array(pd);\n        pd->array[pd->array_length] = *block;\n        pd->array_length++;\n        g_free(block);\n        changed = TRUE;\n      }\n      if (changed) {\n        rofi_view_reload();\n      }\n    } else if (command == 'q') {\n      if (pd->loading) {\n        // TODO: add enable.\n        // rofi_view_set_overlay(rofi_view_get_active(), NULL);\n      }\n    }\n  }\n  return G_SOURCE_CONTINUE;\n}\n\nstatic int recursive_browser_mode_init(Mode *sw) {\n  /**\n   * Called on startup when enabled (in modes list)\n   */\n  if (mode_get_private_data(sw) == NULL) {\n    FileBrowserModePrivateData *pd = g_malloc0(sizeof(*pd));\n    mode_set_private_data(sw, (void *)pd);\n\n    recursive_browser_mode_init_config(sw);\n    recursive_browser_mode_init_current_dir(sw);\n\n    // Load content.\n    if (pipe(pd->pipefd2) == -1) {\n      g_error(\"Failed to create pipe\");\n    }\n    pd->wake_source = g_unix_fd_add(pd->pipefd2[0], G_IO_IN,\n                                    recursive_browser_async_read_proc, pd);\n\n    // Create the message passing queue to the UI thread.\n    pd->async_queue = g_async_queue_new();\n    pd->end_thread = FALSE;\n    pd->reading_thread =\n        g_thread_new(\"recursivebrowser-read\",\n                     (GThreadFunc)recursive_browser_input_thread, pd);\n    pd->loading = TRUE;\n  }\n  return TRUE;\n}\nstatic unsigned int recursive_browser_mode_get_num_entries(const Mode *sw) {\n  const FileBrowserModePrivateData *pd =\n      (const FileBrowserModePrivateData *)mode_get_private_data(sw);\n  return pd->array_length;\n}\n\nstatic ModeMode recursive_browser_mode_result(Mode *sw, int mretv,\n                                              G_GNUC_UNUSED char **input,\n                                              unsigned int selected_line) {\n  ModeMode retv = MODE_EXIT;\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  if ((mretv & MENU_CANCEL) == MENU_CANCEL) {\n    ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"cancel-returns-1\", TRUE);\n    if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n      rofi_set_return_code(1);\n    }\n\n    return MODE_EXIT;\n  }\n  if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  } else if ((mretv & MENU_OK)) {\n    if (selected_line < pd->array_length) {\n      if (pd->array[selected_line].type == RFILE) {\n        char *d_esc = g_shell_quote(pd->array[selected_line].path);\n        char *cmd = g_strdup_printf(\"%s %s\", pd->command, d_esc);\n        g_free(d_esc);\n        char *cdir = g_file_get_path(pd->current_dir);\n        helper_execute_command(cdir, cmd, FALSE, NULL);\n        g_free(cdir);\n        g_free(cmd);\n        return MODE_EXIT;\n      }\n    }\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_CUSTOM_INPUT)) {\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {\n    retv = RELOAD_DIALOG;\n  }\n  return retv;\n}\n\nstatic void recursive_browser_mode_destroy(Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if (pd != NULL) {\n    if (pd->reading_thread) {\n      pd->end_thread = TRUE;\n      g_thread_join(pd->reading_thread);\n    }\n    if (pd->filter_regex) {\n      g_regex_unref(pd->filter_regex);\n    }\n    g_object_unref(pd->current_dir);\n    g_free(pd->command);\n    free_list(pd);\n    g_free(pd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                G_GNUC_UNUSED int *state,\n                                G_GNUC_UNUSED GList **attr_list,\n                                int get_entry) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  // Only return the string if requested, otherwise only set state.\n  if (!get_entry) {\n    return NULL;\n  }\n  if (pd->array[selected_line].type == UP) {\n    return g_strdup(\" ..\");\n  }\n  if (pd->array[selected_line].link) {\n    return g_strconcat(\"@\", pd->array[selected_line].name, NULL);\n  }\n  return g_strdup(pd->array[selected_line].name);\n}\n\n/**\n * @param sw The mode object.\n * @param tokens The tokens to match against.\n * @param index  The index in this plugin to match against.\n *\n * Match the entry.\n *\n * @returns try when a match.\n */\nstatic int recursive_browser_token_match(const Mode *sw,\n                                         rofi_int_matcher **tokens,\n                                         unsigned int index) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  // Call default matching function.\n  return helper_token_match(tokens, pd->array[index].name);\n}\n\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int height) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n  g_return_val_if_fail(pd->array != NULL, NULL);\n  FBFile *dr = &(pd->array[selected_line]);\n  if (rofi_icon_fetcher_file_is_image(dr->path)) {\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(dr->path, height);\n  } else if (dr->type == RFILE) {\n    gchar *_path = g_strconcat(\"thumbnail://\", dr->path, NULL);\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(_path, height);\n    g_free(_path);\n  } else {\n    dr->icon_fetch_uid =\n        rofi_icon_fetcher_query(rb_icon_name[dr->type], height);\n  }\n  dr->icon_fetch_size = height;\n  dr->icon_fetch_scale = scale;\n  return rofi_icon_fetcher_get(dr->icon_fetch_uid);\n}\n\nstatic char *_get_message(const Mode *sw) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if (pd->current_dir) {\n    char *dirname = g_file_get_parse_name(pd->current_dir);\n    char *str =\n        g_markup_printf_escaped(\"<b>Current directory:</b> %s\", dirname);\n    g_free(dirname);\n    return str;\n  }\n  return \"n/a\";\n}\n\nstatic char *_get_completion(const Mode *sw, unsigned int index) {\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n\n  char *d = g_strescape(pd->array[index].path, NULL);\n  return d;\n}\n\nMode *create_new_recursive_browser(void) {\n  Mode *sw = g_malloc0(sizeof(Mode));\n\n  *sw = recursive_browser_mode;\n\n  sw->private_data = NULL;\n  return sw;\n}\n\n#if 1\nModeMode recursive_browser_mode_completer(Mode *sw, int mretv, char **input,\n                                          unsigned int selected_line,\n                                          char **path) {\n  ModeMode retv = MODE_EXIT;\n  FileBrowserModePrivateData *pd =\n      (FileBrowserModePrivateData *)mode_get_private_data(sw);\n  if ((mretv & MENU_OK)) {\n    if (selected_line < pd->array_length) {\n      if (pd->array[selected_line].type == RFILE) {\n        *path = g_strescape(pd->array[selected_line].path, NULL);\n        return MODE_EXIT;\n      }\n    }\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input) {\n    retv = RELOAD_DIALOG;\n  } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {\n    retv = RELOAD_DIALOG;\n  }\n  return retv;\n}\n#endif\n\nMode recursive_browser_mode = {\n    .display_name = NULL,\n    .abi_version = ABI_VERSION,\n    .name = \"recursivebrowser\",\n    .cfg_name_key = \"display-recursivebrowser\",\n    ._init = recursive_browser_mode_init,\n    ._get_num_entries = recursive_browser_mode_get_num_entries,\n    ._result = recursive_browser_mode_result,\n    ._destroy = recursive_browser_mode_destroy,\n    ._token_match = recursive_browser_token_match,\n    ._get_display_value = _get_display_value,\n    ._get_icon = _get_icon,\n    ._get_message = _get_message,\n    ._get_completion = _get_completion,\n    ._preprocess_input = NULL,\n    ._create = create_new_recursive_browser,\n    ._completer_result = recursive_browser_mode_completer,\n    .private_data = NULL,\n    .free = NULL,\n    .type = MODE_TYPE_SWITCHER | MODE_TYPE_COMPLETER};\n"
  },
  {
    "path": "source/modes/run.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/**\n * \\ingroup RUNMode\n * @{\n */\n\n/** The log domain of this dialog. */\n#define G_LOG_DOMAIN \"Modes.Run\"\n\n#include \"config.h\"\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <dirent.h>\n#include <errno.h>\n#include <limits.h>\n#include <signal.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"history.h\"\n#include \"modes/filebrowser.h\"\n#include \"modes/run.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n\n#include \"mode-private.h\"\n\n#include \"rofi-icon-fetcher.h\"\n#include \"timings.h\"\n/**\n * Name of the history file where previously chosen commands are stored.\n */\n#define RUN_CACHE_FILE \"rofi-4.runcache\"\n\ntypedef struct {\n  char *entry;\n  char *exec;\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  gboolean from_history;\n  /* Surface holding the icon. */\n  cairo_surface_t *icon;\n} RunEntry;\n\n/**\n * The internal data structure holding the private data of the Run Mode.\n */\ntypedef struct {\n  /** list of available commands. */\n  RunEntry *cmd_list;\n  /** Length of the #cmd_list. */\n  unsigned int cmd_list_length;\n\n  /** Current mode. */\n  gboolean file_complete;\n  uint32_t selected_line;\n  char *old_input;\n\n  Mode *completer;\n  char *old_completer_input;\n} RunModePrivateData;\n\n/**\n * @param cmd The cmd to execute\n * @param run_in_term Indicate if command should be run in a terminal\n * @param orig The cmd to store in history\n *\n * Execute command and add to history.\n * Exact entries should be stored unquoted any custom or with filename\n * should be saved in history quoted.\n */\nstatic gboolean exec_cmd(const char *cmd, int run_in_term, const char *orig) {\n  GError *error = NULL;\n  if (!cmd || !cmd[0]) {\n    return FALSE;\n  }\n  gsize lf_cmd_size = 0;\n  gchar *lf_cmd = g_locale_from_utf8(cmd, -1, NULL, &lf_cmd_size, &error);\n  if (error != NULL) {\n    g_warning(\"Failed to convert command to locale encoding: %s\",\n              error->message);\n    g_error_free(error);\n    return FALSE;\n  }\n\n  char *path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);\n  RofiHelperExecuteContext context = {.name = NULL};\n  char *hist = g_strdup_printf(\"%s\\x1f%s\", orig, cmd);\n  // FIXME: assume startup notification support for terminals\n  if (helper_execute_command(NULL, lf_cmd, run_in_term,\n                             run_in_term ? &context : NULL)) {\n    /**\n     * This happens in non-critical time (After launching app)\n     * It is allowed to be a bit slower.\n     */\n\n    history_set(path, hist);\n    g_free(path);\n    g_free(lf_cmd);\n    g_free(hist);\n    return TRUE;\n  }\n  history_remove(path, hist);\n  g_free(hist);\n  g_free(path);\n  g_free(lf_cmd);\n  return FALSE;\n}\n\n/**\n * @param cmd The command to remove from history\n *\n * Remove command from history.\n */\nstatic void delete_entry(const RunEntry *cmd) {\n  char *path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);\n\n  char *hist = g_strdup_printf(\"%s\\x1f%s\", cmd->entry, cmd->exec);\n  history_remove(path, hist);\n  g_free(hist);\n  g_free(path);\n}\n\n/**\n * @param a The First key to compare\n * @param b The second key to compare\n * @param data Unused.\n *\n * Function used for sorting.\n *\n * @returns returns less then, equal to and greater than zero is a is less than,\n * is a match or greater than b.\n */\nstatic int sort_func(const void *a, const void *b, G_GNUC_UNUSED void *data) {\n  const RunEntry *astr = (const RunEntry *)a;\n  const RunEntry *bstr = (const RunEntry *)b;\n\n  if (astr->entry == NULL && bstr->entry == NULL) {\n    return 0;\n  }\n  if (astr->entry == NULL) {\n    return 1;\n  }\n  if (bstr->entry == NULL) {\n    return -1;\n  }\n  return g_strcmp0(astr->entry, bstr->entry);\n}\n\n/**\n * External spider to get list of executables.\n */\nstatic RunEntry *get_apps_external(RunEntry *retv, unsigned int *length,\n                                   unsigned int num_favorites) {\n  int fd = execute_generator(config.run_list_command);\n  if (fd >= 0) {\n    FILE *inp = fdopen(fd, \"r\");\n    if (inp) {\n      char *buffer = NULL;\n      size_t buffer_length = 0;\n\n      while (getline(&buffer, &buffer_length, inp) > 0) {\n        int found = 0;\n        // Filter out line-end.\n        if (buffer[strlen(buffer) - 1] == '\\n') {\n          buffer[strlen(buffer) - 1] = '\\0';\n        }\n\n        // This is a nice little penalty, but doable? time will tell.\n        // given num_favorites is max 25.\n        for (unsigned int j = 0; found == 0 && j < num_favorites; j++) {\n          if (strcasecmp(buffer, retv[j].entry) == 0) {\n            found = 1;\n          }\n        }\n\n        if (found == 1) {\n          continue;\n        }\n\n        // No duplicate, add it.\n        retv = g_realloc(retv, ((*length) + 2) * sizeof(RunEntry));\n        retv[(*length)].entry = g_strdup(buffer);\n        retv[(*length)].exec = g_shell_quote(buffer);\n        retv[(*length)].from_history = FALSE;\n        retv[(*length)].icon = NULL;\n        retv[(*length)].icon_fetch_uid = 0;\n        retv[(*length)].icon_fetch_size = 0;\n\n        (*length)++;\n      }\n      if (buffer != NULL) {\n        free(buffer);\n      }\n      if (fclose(inp) != 0) {\n        g_warning(\"Failed to close stdout off executor script: '%s'\",\n                  g_strerror(errno));\n      }\n    }\n  }\n  retv[(*length)].entry = NULL;\n  retv[(*length)].exec = NULL;\n  retv[(*length)].from_history = FALSE;\n  retv[(*length)].icon = NULL;\n  retv[(*length)].icon_fetch_uid = 0;\n  retv[(*length)].icon_fetch_size = 0;\n  return retv;\n}\n\n/**\n * Internal spider used to get list of executables.\n */\nstatic RunEntry *get_apps(unsigned int *length) {\n  GError *error = NULL;\n  RunEntry *retv = NULL;\n  unsigned int num_favorites = 0;\n  char *path;\n\n  if (g_getenv(\"PATH\") == NULL) {\n    return NULL;\n  }\n  TICK_N(\"start\");\n  path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);\n  char **hretv = history_get_list(path, length);\n  retv = (RunEntry *)g_malloc0((*length + 1) * sizeof(RunEntry));\n  for (unsigned int i = 0; i < *length; i++) {\n    gchar **rs = g_strsplit(hretv[i], \"\\x1f\", 2);\n    retv[i].entry = rs[0];\n    retv[i].exec = rs[1];\n    if (retv[i].exec == NULL) {\n      retv[i].exec = g_strdup(rs[0]);\n    }\n    retv[i].from_history = TRUE;\n    g_free(rs);\n  }\n  g_free(hretv);\n  g_free(path);\n  // Keep track of how many where loaded as favorite.\n  num_favorites = (*length);\n\n  path = g_strdup(g_getenv(\"PATH\"));\n\n  gsize l = 0;\n  gchar *homedir = g_locale_to_utf8(g_get_home_dir(), -1, NULL, &l, &error);\n  if (error != NULL) {\n    g_debug(\"Failed to convert homedir to UTF-8: %s\", error->message);\n    for (unsigned int i = 0; retv[i].entry != NULL; i++) {\n      g_free(retv[i].entry);\n      g_free(retv[i].exec);\n    }\n    g_free(retv);\n    g_clear_error(&error);\n    g_free(homedir);\n    return NULL;\n  }\n\n  const char *const sep = \":\";\n  char *strtok_savepointer = NULL;\n  for (const char *dirname = strtok_r(path, sep, &strtok_savepointer);\n       dirname != NULL; dirname = strtok_r(NULL, sep, &strtok_savepointer)) {\n    char *fpath = rofi_expand_path(dirname);\n    DIR *dir = opendir(fpath);\n    g_debug(\"Checking path %s for executable.\", fpath);\n    g_free(fpath);\n\n    if (dir != NULL) {\n      struct dirent *dent;\n      gsize dirn_len = 0;\n      gchar *dirn = g_locale_to_utf8(dirname, -1, NULL, &dirn_len, &error);\n      if (error != NULL) {\n        g_debug(\"Failed to convert directory name to UTF-8: %s\",\n                error->message);\n        g_clear_error(&error);\n        closedir(dir);\n        continue;\n      }\n      gboolean is_homedir = g_str_has_prefix(dirn, homedir);\n      g_free(dirn);\n\n      while ((dent = readdir(dir)) != NULL) {\n        if (dent->d_type != DT_REG && dent->d_type != DT_LNK &&\n            dent->d_type != DT_UNKNOWN) {\n          continue;\n        }\n        // Skip dot files.\n        if (dent->d_name[0] == '.') {\n          continue;\n        }\n        if (is_homedir) {\n          gchar *full_path = g_build_filename(dirname, dent->d_name, NULL);\n          gboolean b = g_file_test(full_path, G_FILE_TEST_IS_EXECUTABLE);\n          g_free(full_path);\n          if (!b) {\n            continue;\n          }\n        }\n\n        gsize name_len;\n        gchar *name =\n            g_filename_to_utf8(dent->d_name, -1, NULL, &name_len, &error);\n        if (error != NULL) {\n          g_debug(\"Failed to convert filename to UTF-8: %s\", error->message);\n          g_clear_error(&error);\n          g_free(name);\n          continue;\n        }\n        // This is a nice little penalty, but doable? time will tell.\n        // given num_favorites is max 25.\n        int found = 0;\n        for (unsigned int j = 0; found == 0 && j < num_favorites; j++) {\n          if (g_strcmp0(name, retv[j].entry) == 0) {\n            found = 1;\n          }\n        }\n\n        if (found == 1) {\n          g_free(name);\n          continue;\n        }\n\n        retv = g_realloc(retv, ((*length) + 2) * sizeof(RunEntry));\n        retv[(*length)].entry = name;\n        retv[(*length)].exec = g_shell_quote(name);\n        retv[(*length)].from_history = FALSE;\n        retv[(*length)].icon = NULL;\n        retv[(*length)].icon_fetch_uid = 0;\n        retv[(*length)].icon_fetch_size = 0;\n        retv[(*length) + 1].entry = NULL;\n        retv[(*length) + 1].exec = NULL;\n        retv[(*length) + 1].from_history = FALSE;\n        retv[(*length) + 1].icon = NULL;\n        retv[(*length) + 1].icon_fetch_uid = 0;\n        retv[(*length) + 1].icon_fetch_size = 0;\n        (*length)++;\n      }\n\n      closedir(dir);\n    }\n  }\n  g_free(homedir);\n\n  // Get external apps.\n  if (config.run_list_command != NULL && config.run_list_command[0] != '\\0') {\n    retv = get_apps_external(retv, length, num_favorites);\n  }\n  // No sorting needed.\n  if ((*length) == 0) {\n    return retv;\n  }\n  // TODO: check this is still fast enough. (takes 1ms on laptop.)\n  if ((*length) > num_favorites) {\n    g_qsort_with_data(&(retv[num_favorites]), (*length) - num_favorites,\n                      sizeof(RunEntry), sort_func, NULL);\n  }\n  g_free(path);\n\n  unsigned int removed = 0;\n  for (unsigned int index = num_favorites; index < ((*length) - 1); index++) {\n    if (g_strcmp0(retv[index].entry, retv[index + 1].entry) == 0) {\n      g_free(retv[index].entry);\n      retv[index].entry = NULL;\n      g_free(retv[index].exec);\n      retv[index].exec = NULL;\n      removed++;\n    }\n  }\n\n  if ((*length) > num_favorites) {\n    g_qsort_with_data(&(retv[num_favorites]), (*length) - num_favorites,\n                      sizeof(RunEntry), sort_func, NULL);\n  }\n  // Reduce array length;\n  (*length) -= removed;\n\n  TICK_N(\"stop\");\n  return retv;\n}\n\nstatic int run_mode_init(Mode *sw) {\n  if (sw->private_data == NULL) {\n    RunModePrivateData *pd = g_malloc0(sizeof(*pd));\n    sw->private_data = (void *)pd;\n    pd->cmd_list = get_apps(&(pd->cmd_list_length));\n    pd->completer = NULL;\n  }\n\n  return TRUE;\n}\nstatic void run_mode_destroy(Mode *sw) {\n  RunModePrivateData *rmpd = (RunModePrivateData *)sw->private_data;\n  if (rmpd != NULL) {\n    for (unsigned int i = 0; i < rmpd->cmd_list_length; i++) {\n      g_free(rmpd->cmd_list[i].entry);\n      g_free(rmpd->cmd_list[i].exec);\n      if (rmpd->cmd_list[i].icon != NULL) {\n        cairo_surface_destroy(rmpd->cmd_list[i].icon);\n      }\n    }\n    g_free(rmpd->cmd_list);\n    g_free(rmpd->old_input);\n    g_free(rmpd->old_completer_input);\n    if (rmpd->completer != NULL) {\n      mode_destroy(rmpd->completer);\n      g_free(rmpd->completer);\n    }\n    g_free(rmpd);\n    sw->private_data = NULL;\n  }\n}\n\nstatic unsigned int run_mode_get_num_entries(const Mode *sw) {\n  const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;\n  if (rmpd->file_complete) {\n    return rmpd->completer->_get_num_entries(rmpd->completer);\n  }\n  return rmpd->cmd_list_length;\n}\n\nstatic ModeMode run_mode_result(Mode *sw, int mretv, char **input,\n                                unsigned int selected_line) {\n  RunModePrivateData *rmpd = (RunModePrivateData *)sw->private_data;\n  ModeMode retv = MODE_EXIT;\n\n  gboolean run_in_term = ((mretv & MENU_CUSTOM_ACTION) == MENU_CUSTOM_ACTION);\n  if (rmpd->file_complete == TRUE) {\n\n    retv = RELOAD_DIALOG;\n\n    if ((mretv & (MENU_COMPLETE))) {\n      g_free(rmpd->old_completer_input);\n      rmpd->old_completer_input = *input;\n      *input = NULL;\n      if (rmpd->selected_line < rmpd->cmd_list_length) {\n        (*input) = g_strdup(rmpd->old_input);\n      }\n      rmpd->file_complete = FALSE;\n    } else if ((mretv & MENU_CANCEL)) {\n      retv = MODE_EXIT;\n    } else {\n      char *path = NULL;\n      retv = mode_completer_result(rmpd->completer, mretv, input, selected_line,\n                                   &path);\n      if (retv == MODE_EXIT) {\n        if (path == NULL) {\n          char *arg = rmpd->cmd_list[rmpd->selected_line].exec;\n          exec_cmd(arg, run_in_term, rmpd->cmd_list[rmpd->selected_line].entry);\n        } else {\n          char *earg = rmpd->cmd_list[rmpd->selected_line].exec;\n          char *epath = g_shell_quote(path);\n          char *arg = g_strdup_printf(\"%s %s\", earg, epath);\n          exec_cmd(arg, run_in_term, arg);\n          g_free(arg);\n          g_free(epath);\n        }\n      }\n      g_free(path);\n    }\n    return retv;\n  }\n\n  if ((mretv & MENU_OK) && rmpd->cmd_list[selected_line].entry != NULL) {\n    char *earg = NULL;\n    earg = rmpd->cmd_list[selected_line].exec;\n    if (!exec_cmd(earg, run_in_term, rmpd->cmd_list[selected_line].entry)) {\n      retv = RELOAD_DIALOG;\n    }\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&\n             *input[0] != '\\0') {\n    if (!exec_cmd(*input, run_in_term, *input)) {\n      retv = RELOAD_DIALOG;\n    }\n  } else if ((mretv & MENU_ENTRY_DELETE) &&\n             rmpd->cmd_list[selected_line].entry) {\n    delete_entry(&(rmpd->cmd_list[selected_line]));\n\n    // Clear the list.\n    retv = RELOAD_DIALOG;\n    run_mode_destroy(sw);\n    run_mode_init(sw);\n  } else if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  } else if ((mretv & MENU_COMPLETE)) {\n    retv = RELOAD_DIALOG;\n    if (selected_line < rmpd->cmd_list_length) {\n      rmpd->selected_line = selected_line;\n\n      g_free(rmpd->old_input);\n      rmpd->old_input = g_strdup(*input);\n\n      if (*input)\n        g_free(*input);\n      *input = g_strdup(rmpd->old_completer_input);\n\n      const Mode *comp = rofi_get_completer();\n      if (comp) {\n        rmpd->completer = mode_create(comp);\n        mode_init(rmpd->completer);\n        rmpd->file_complete = TRUE;\n      }\n    }\n  }\n  return retv;\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                G_GNUC_UNUSED int *state,\n                                G_GNUC_UNUSED GList **list, int get_entry) {\n  const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;\n  if (rmpd->file_complete) {\n    return rmpd->completer->_get_display_value(rmpd->completer, selected_line,\n                                               state, list, get_entry);\n  }\n  return get_entry ? g_strdup(rmpd->cmd_list[selected_line].entry) : NULL;\n}\n\nstatic int run_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                           unsigned int index) {\n  const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;\n  if (rmpd->file_complete) {\n    return rmpd->completer->_token_match(rmpd->completer, tokens, index);\n  }\n  return helper_token_match(tokens, rmpd->cmd_list[index].entry);\n}\nstatic char *run_get_message(const Mode *sw) {\n  RunModePrivateData *pd = sw->private_data;\n  if (pd->file_complete) {\n    if (pd->selected_line < pd->cmd_list_length) {\n      char *msg = mode_get_message(pd->completer);\n      if (msg) {\n        char *retv =\n            g_strdup_printf(\"File complete for: %s\\n%s\",\n                            pd->cmd_list[pd->selected_line].entry, msg);\n        g_free(msg);\n        return retv;\n      }\n      return g_strdup_printf(\"File complete for: %s\",\n                             pd->cmd_list[pd->selected_line].entry);\n    }\n  }\n  return NULL;\n}\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int height) {\n  RunModePrivateData *pd = (RunModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n  if (pd->file_complete) {\n    return pd->completer->_get_icon(pd->completer, selected_line, height);\n  }\n  g_return_val_if_fail(pd->cmd_list != NULL, NULL);\n  RunEntry *dr = &(pd->cmd_list[selected_line]);\n\n  if (dr->icon_fetch_uid > 0 && dr->icon_fetch_size == height &&\n      dr->icon_fetch_scale == scale) {\n    cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);\n    return icon;\n  }\n  /** lookup icon */\n  char **str = g_strsplit(dr->entry, \" \", 2);\n  if (str) {\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(str[0], height);\n    dr->icon_fetch_size = height;\n    dr->icon_fetch_scale = scale;\n    g_strfreev(str);\n    cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);\n    return icon;\n  }\n  return NULL;\n}\n\n#include \"mode-private.h\"\nMode run_mode = {.name = \"run\",\n                 .cfg_name_key = \"display-run\",\n                 ._init = run_mode_init,\n                 ._get_num_entries = run_mode_get_num_entries,\n                 ._result = run_mode_result,\n                 ._destroy = run_mode_destroy,\n                 ._token_match = run_token_match,\n                 ._get_message = run_get_message,\n                 ._get_display_value = _get_display_value,\n                 ._get_icon = _get_icon,\n                 ._get_completion = NULL,\n                 ._preprocess_input = NULL,\n                 .private_data = NULL,\n                 .free = NULL,\n                 .type = MODE_TYPE_SWITCHER};\n/** @}*/\n"
  },
  {
    "path": "source/modes/script.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#define G_LOG_DOMAIN \"Modes.Script\"\n\n/** The log domain of this dialog. */\n#include \"glib.h\"\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"modes/script.h\"\n#include \"rofi.h\"\n#include <assert.h>\n#include <ctype.h>\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <unistd.h>\n\n#include \"widgets/textbox.h\"\n\n#include \"mode-private.h\"\n\n#include \"rofi-icon-fetcher.h\"\n\n#include \"modes/dmenuscriptshared.h\"\n\ntypedef struct {\n  /** ID of the current script. */\n  unsigned int id;\n  /** List of visible items. */\n  DmenuScriptEntry *cmd_list;\n  /** length list of visible items. */\n  unsigned int cmd_list_length;\n\n  /** Urgent list */\n  struct rofi_range_pair *urgent_list;\n  unsigned int num_urgent_list;\n  /** Active list */\n  struct rofi_range_pair *active_list;\n  unsigned int num_active_list;\n  /** Configuration settings. */\n  char *message;\n  char *prompt;\n  char *data;\n  gboolean do_markup;\n  gboolean keep_selection;\n  int64_t new_selection;\n  char delim;\n  /** no custom */\n  gboolean no_custom;\n  /** keep filter */\n  gboolean keep_filter;\n\n  gboolean use_hot_keys;\n\n  int switch_mode;\n} ScriptModePrivateData;\n\n/**\n * Shared function between DMENU and Script mode.\n */\nvoid dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw,\n                                    DmenuScriptEntry *entry, char *buffer,\n                                    G_GNUC_UNUSED size_t length) {\n  gchar **extras = g_strsplit(buffer, \"\\x1f\", -1);\n  gchar **extra = extras;\n  for (; *extra != NULL && *(extra + 1) != NULL; extra += 2) {\n    gchar *key = *extra;\n    gchar *value = *(extra + 1);\n    // Mark NULL\n    *(extra) = NULL;\n    *(extra + 1) = NULL;\n    if (strcasecmp(key, \"icon\") == 0) {\n      entry->icon_name = g_strsplit(value, \",\", -1);\n      g_free(value);\n    } else if (strcasecmp(key, \"display\") == 0) {\n      entry->display = value;\n    } else if (strcasecmp(key, \"meta\") == 0) {\n      entry->meta = value;\n    } else if (strcasecmp(key, \"info\") == 0) {\n      entry->info = value;\n    } else if (strcasecmp(key, \"nonselectable\") == 0) {\n      entry->nonselectable = g_ascii_strcasecmp(value, \"true\") == 0;\n      g_free(value);\n    } else if (strcasecmp(key, \"permanent\") == 0) {\n      entry->permanent = g_ascii_strcasecmp(value, \"true\") == 0;\n      g_free(value);\n    } else if (strcasecmp(key, \"urgent\") == 0) {\n      entry->urgent = g_ascii_strcasecmp(value, \"true\") == 0;\n      g_free(value);\n    } else if (strcasecmp(key, \"active\") == 0) {\n      entry->active = g_ascii_strcasecmp(value, \"true\") == 0;\n      g_free(value);\n    } else {\n      g_free(value);\n    }\n    g_free(key);\n  }\n  // Got an extra entry.. lets free it.\n  if (*extras != NULL) {\n    g_free(*extras);\n  }\n  g_free(extras);\n}\n\n/**\n * End of shared functions.\n */\n\nstatic void script_switch_mode(Mode *sw, char *value) {\n  int index = mode_lookup(value);\n  ScriptModePrivateData *pd = (ScriptModePrivateData *)sw->private_data;\n\n  if (index >= 0) {\n    pd->switch_mode = index;\n  } else {\n    g_warning(\"Mode \\\"%s\\\" not found, please make sure it's enabled.\\n\", value);\n  }\n}\n\nstatic void parse_header_entry(Mode *sw, char *line, ssize_t length) {\n  ScriptModePrivateData *pd = (ScriptModePrivateData *)sw->private_data;\n  ssize_t length_key = 0; // strlen ( line );\n  while (length_key < length && line[length_key] != '\\x1f') {\n    length_key++;\n  }\n\n  if ((length_key + 1) < length) {\n    line[length_key] = '\\0';\n    char *value = line + length_key + 1;\n    if (strcasecmp(line, \"message\") == 0) {\n      g_free(pd->message);\n      pd->message = strlen(value) ? g_strdup(value) : NULL;\n    } else if (strcasecmp(line, \"prompt\") == 0) {\n      g_free(pd->prompt);\n      pd->prompt = g_strdup(value);\n      sw->display_name = pd->prompt;\n    } else if (strcasecmp(line, \"markup-rows\") == 0) {\n      pd->do_markup = (strcasecmp(value, \"true\") == 0);\n    } else if (strcasecmp(line, \"urgent\") == 0) {\n      parse_ranges(value, &(pd->urgent_list), &(pd->num_urgent_list));\n    } else if (strcasecmp(line, \"active\") == 0) {\n      parse_ranges(value, &(pd->active_list), &(pd->num_active_list));\n    } else if (strcasecmp(line, \"delim\") == 0) {\n      pd->delim = helper_parse_char(value);\n    } else if (strcasecmp(line, \"no-custom\") == 0) {\n      pd->no_custom = (strcasecmp(value, \"true\") == 0);\n    } else if (strcasecmp(line, \"use-hot-keys\") == 0) {\n      pd->use_hot_keys = (strcasecmp(value, \"true\") == 0);\n    } else if (strcasecmp(line, \"keep-selection\") == 0) {\n      pd->keep_selection = (strcasecmp(value, \"true\") == 0);\n    } else if (strcasecmp(line, \"keep-filter\") == 0) {\n      pd->keep_filter = (strcasecmp(value, \"true\") == 0);\n    } else if (strcasecmp(line, \"new-selection\") == 0) {\n      pd->new_selection = (int64_t)g_ascii_strtoll(value, NULL, 0);\n    } else if (strcasecmp(line, \"data\") == 0) {\n      g_free(pd->data);\n      pd->data = g_strdup(value);\n    } else if (strcasecmp(line, \"theme\") == 0) {\n      if (rofi_theme_parse_string((const char *)value)) {\n        g_warning(\"Failed to parse: '%s'\", value);\n        rofi_clear_error_messages();\n      }\n    } else if (strcasecmp(line, \"switch-mode\") == 0) {\n      script_switch_mode(sw, value);\n    }\n  }\n}\n\nstatic DmenuScriptEntry *execute_executor(Mode *sw, char *arg,\n                                          unsigned int *length, int value,\n                                          DmenuScriptEntry *entry,\n                                          char *input) {\n  ScriptModePrivateData *pd = (ScriptModePrivateData *)sw->private_data;\n  int fd = -1;\n  GError *error = NULL;\n  DmenuScriptEntry *retv = NULL;\n  char **argv = NULL;\n  int argc = 0;\n  *length = 0;\n  // Reset these between runs.\n  pd->new_selection = -1;\n  pd->keep_selection = 0;\n  pd->keep_filter = 0;\n  // Environment\n  char **env = g_get_environ();\n\n  char *str_value = g_strdup_printf(\"%d\", value);\n  env = g_environ_setenv(env, \"ROFI_RETV\", str_value, TRUE);\n  g_free(str_value);\n\n  str_value = g_strdup_printf(\"%d\", (int)getpid());\n  env = g_environ_setenv(env, \"ROFI_OUTSIDE\", str_value, TRUE);\n  g_free(str_value);\n\n  if (entry && entry->info) {\n    env = g_environ_setenv(env, \"ROFI_INFO\", entry->info, TRUE);\n  }\n  if (pd->data) {\n    env = g_environ_setenv(env, \"ROFI_DATA\", pd->data, TRUE);\n  }\n\n  if (input != NULL) {\n    env = g_environ_setenv(env, \"ROFI_INPUT\", input, TRUE);\n  }\n\n  if (g_shell_parse_argv(sw->ed, &argc, &argv, &error)) {\n    argv = g_realloc(argv, (argc + 2) * sizeof(char *));\n    argv[argc] = g_strdup(arg);\n    argv[argc + 1] = NULL;\n    g_spawn_async_with_pipes(NULL, argv, env, G_SPAWN_SEARCH_PATH, NULL, NULL,\n                             NULL, NULL, &fd, NULL, &error);\n  }\n  g_strfreev(env);\n  if (error != NULL) {\n    char *msg = g_strdup_printf(\"Failed to execute: '%s'\\nError: '%s'\",\n                                (char *)sw->ed, error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n    fd = -1;\n  }\n  if (fd >= 0) {\n    FILE *inp = fdopen(fd, \"r\");\n    if (inp) {\n      char *buffer = NULL;\n      size_t buffer_length = 0;\n      ssize_t read_length = 0;\n      size_t actual_size = 0;\n      while ((read_length = getdelim(&buffer, &buffer_length, pd->delim, inp)) >\n             0) {\n        // Filter out line-end.\n        if (buffer[read_length - 1] == pd->delim) {\n          buffer[read_length - 1] = '\\0';\n        }\n        if (buffer[0] == '\\0') {\n          parse_header_entry(sw, &buffer[1], read_length - 1);\n        } else {\n          if (actual_size < ((*length) + 2)) {\n            actual_size += 256;\n            // Check if it returns NULL, if it does, break out and show what we\n            // have so far.\n            DmenuScriptEntry *retvn =\n                g_realloc(retv, (actual_size) * sizeof(DmenuScriptEntry));\n            if (retvn == NULL) {\n              break;\n            }\n            retv = retvn;\n          }\n          if (retv) {\n            size_t buf_length = strlen(buffer) + 1;\n#if GLIB_CHECK_VERSION(2, 68, 0)\n            retv[(*length)].entry = g_memdup2(buffer, buf_length);\n#else\n            retv[(*length)].entry = g_memdup(buffer, buf_length);\n#endif\n            retv[(*length)].icon_name = NULL;\n            retv[(*length)].display = NULL;\n            retv[(*length)].meta = NULL;\n            retv[(*length)].info = NULL;\n            retv[(*length)].active = FALSE;\n            retv[(*length)].urgent = FALSE;\n            retv[(*length)].icon_fetch_uid = 0;\n            retv[(*length)].icon_fetch_size = 0;\n            retv[(*length)].icon_fetch_scale = 0;\n            retv[(*length)].nonselectable = FALSE;\n            retv[(*length)].permanent = FALSE;\n            if (buf_length > 0 && (read_length > (ssize_t)buf_length)) {\n              dmenuscript_parse_entry_extras(sw, &(retv[(*length)]),\n                                             buffer + buf_length,\n                                             read_length - buf_length);\n            }\n            memset(&(retv[(*length) + 1]), 0, sizeof(DmenuScriptEntry));\n            (*length)++;\n          }\n        }\n      }\n      if (buffer) {\n        free(buffer);\n      }\n      if (fclose(inp) != 0) {\n        g_warning(\"Failed to close stdout off executor script: '%s'\",\n                  g_strerror(errno));\n      }\n    }\n  }\n  g_strfreev(argv);\n  return retv;\n}\n\nstatic void script_switcher_free(Mode *sw) {\n  if (sw == NULL) {\n    return;\n  }\n  g_free(sw->name);\n  g_free(sw->ed);\n  g_free(sw);\n}\n\nstatic int script_mode_init(Mode *sw) {\n  if (sw->private_data == NULL) {\n    ScriptModePrivateData *pd = g_malloc0(sizeof(*pd));\n    pd->delim = '\\n';\n    sw->private_data = (void *)pd;\n    pd->cmd_list =\n        execute_executor(sw, NULL, &(pd->cmd_list_length), 0, NULL, NULL);\n    pd->switch_mode = -1;\n  }\n  return TRUE;\n}\nstatic unsigned int script_mode_get_num_entries(const Mode *sw) {\n  const ScriptModePrivateData *rmpd =\n      (const ScriptModePrivateData *)sw->private_data;\n  return rmpd->cmd_list_length;\n}\n\nstatic void script_mode_reset_highlight(Mode *sw) {\n  ScriptModePrivateData *rmpd = (ScriptModePrivateData *)sw->private_data;\n\n  rmpd->num_urgent_list = 0;\n  g_free(rmpd->urgent_list);\n  rmpd->urgent_list = NULL;\n  rmpd->num_active_list = 0;\n  g_free(rmpd->active_list);\n  rmpd->active_list = NULL;\n}\n\nstatic void script_mode_free_entry_list(DmenuScriptEntry *list,\n                                        unsigned int length) {\n  for (unsigned int i = 0; i < length; i++) {\n    g_free(list[i].entry);\n    g_strfreev(list[i].icon_name);\n    g_free(list[i].display);\n    g_free(list[i].meta);\n    g_free(list[i].info);\n  }\n  g_free(list);\n}\nstatic ModeMode script_mode_result(Mode *sw, int mretv, char **input,\n                                   unsigned int selected_line) {\n  ScriptModePrivateData *rmpd = (ScriptModePrivateData *)sw->private_data;\n  ModeMode retv = MODE_EXIT;\n  DmenuScriptEntry *new_list = NULL;\n  unsigned int new_length = 0;\n  // store them as they might be different on next executor and reset.\n  gboolean keep_filter = rmpd->keep_filter;\n  gboolean keep_selection = rmpd->keep_selection;\n\n  if ((mretv & MENU_CUSTOM_COMMAND)) {\n    if (rmpd->use_hot_keys) {\n      script_mode_reset_highlight(sw);\n      if (selected_line != UINT32_MAX) {\n        new_list = execute_executor(sw, rmpd->cmd_list[selected_line].entry,\n                                    &new_length, 10 + (mretv & MENU_LOWER_MASK),\n                                    &(rmpd->cmd_list[selected_line]), *input);\n      } else {\n        if (rmpd->no_custom == FALSE) {\n          new_list =\n              execute_executor(sw, *input, &new_length,\n                               10 + (mretv & MENU_LOWER_MASK), NULL, *input);\n        } else {\n          return RELOAD_DIALOG;\n        }\n      }\n    } else {\n      retv = (mretv & MENU_LOWER_MASK);\n      return retv;\n    }\n  } else if ((mretv & MENU_ENTRY_DELETE) && selected_line != UINT32_MAX) {\n    script_mode_reset_highlight(sw);\n    new_list =\n        execute_executor(sw, rmpd->cmd_list[selected_line].entry, &new_length,\n                         3, &(rmpd->cmd_list[selected_line]), *input);\n  } else if ((mretv & MENU_OK) && rmpd->cmd_list[selected_line].entry != NULL) {\n    if (rmpd->cmd_list[selected_line].nonselectable) {\n      return RELOAD_DIALOG;\n    }\n    script_mode_reset_highlight(sw);\n    new_list =\n        execute_executor(sw, rmpd->cmd_list[selected_line].entry, &new_length,\n                         1, &(rmpd->cmd_list[selected_line]), *input);\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL) {\n    if (rmpd->no_custom == FALSE) {\n      script_mode_reset_highlight(sw);\n      new_list = execute_executor(sw, *input, &new_length, 2, NULL, *input);\n    } else {\n      return RELOAD_DIALOG;\n    }\n  }\n\n  if (rmpd->switch_mode >= 0) {\n    script_mode_free_entry_list(new_list, new_length);\n    retv = rmpd->switch_mode;\n    free(*input);\n    *input = NULL;\n    rmpd->switch_mode = -1;\n    return retv;\n  }\n\n  // If a new list was generated, use that an loop around.\n  if (new_list != NULL) {\n    script_mode_free_entry_list(rmpd->cmd_list, rmpd->cmd_list_length);\n    rmpd->cmd_list = new_list;\n    rmpd->cmd_list_length = new_length;\n    if (keep_selection) {\n      if (rmpd->new_selection >= 0 &&\n          rmpd->new_selection < rmpd->cmd_list_length) {\n        rofi_view_set_selected_line(rofi_view_get_active(),\n                                    rmpd->new_selection);\n      } else {\n        rofi_view_set_selected_line(rofi_view_get_active(), selected_line);\n      }\n    } else {\n      rofi_view_set_selected_line(rofi_view_get_active(), 0);\n    }\n    if (keep_filter == FALSE) {\n      g_free(*input);\n      *input = NULL;\n    }\n    retv = RELOAD_DIALOG;\n  }\n  return retv;\n}\n\nstatic void script_mode_destroy(Mode *sw) {\n  ScriptModePrivateData *rmpd = (ScriptModePrivateData *)sw->private_data;\n  if (rmpd != NULL) {\n    script_mode_free_entry_list(rmpd->cmd_list, rmpd->cmd_list_length);\n    g_free(rmpd->message);\n    g_free(rmpd->prompt);\n    g_free(rmpd->data);\n    g_free(rmpd->urgent_list);\n    g_free(rmpd->active_list);\n    g_free(rmpd);\n    sw->private_data = NULL;\n  }\n}\nstatic inline unsigned int get_index(unsigned int length, int index) {\n  if (index >= 0) {\n    return index;\n  }\n  if (((unsigned int)-index) <= length) {\n    return length + index;\n  }\n  // Out of range.\n  return UINT_MAX;\n}\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                G_GNUC_UNUSED int *state,\n                                G_GNUC_UNUSED GList **list, int get_entry) {\n  ScriptModePrivateData *pd = sw->private_data;\n  for (unsigned int i = 0; i < pd->num_active_list; i++) {\n    unsigned int start =\n        get_index(pd->cmd_list_length, pd->active_list[i].start);\n    unsigned int stop = get_index(pd->cmd_list_length, pd->active_list[i].stop);\n    if (selected_line >= start && selected_line <= stop) {\n      *state |= ACTIVE;\n    }\n  }\n  for (unsigned int i = 0; i < pd->num_urgent_list; i++) {\n    unsigned int start =\n        get_index(pd->cmd_list_length, pd->urgent_list[i].start);\n    unsigned int stop = get_index(pd->cmd_list_length, pd->urgent_list[i].stop);\n    if (selected_line >= start && selected_line <= stop) {\n      *state |= URGENT;\n    }\n  }\n  if (pd->cmd_list[selected_line].urgent) {\n    *state |= URGENT;\n  }\n  if (pd->cmd_list[selected_line].active) {\n    *state |= ACTIVE;\n  }\n  if (pd->do_markup) {\n    *state |= MARKUP;\n  }\n  if (pd->cmd_list[selected_line].display) {\n    return get_entry ? g_strdup(pd->cmd_list[selected_line].display) : NULL;\n  } else {\n    return get_entry ? g_strdup(pd->cmd_list[selected_line].entry) : NULL;\n  }\n}\n\nstatic int script_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                              unsigned int index) {\n  ScriptModePrivateData *rmpd = sw->private_data;\n  /** Strip out the markup when matching. */\n  char *esc = NULL;\n\n  if (rmpd->cmd_list[index].permanent == TRUE) {\n    // Always match\n    return 1;\n  }\n\n  if (rmpd->do_markup) {\n    pango_parse_markup(rmpd->cmd_list[index].entry, -1, 0, NULL, &esc, NULL,\n                       NULL);\n  } else {\n    esc = rmpd->cmd_list[index].entry;\n  }\n  if (esc) {\n    int match = 1;\n    if (tokens) {\n      for (int j = 0; match && tokens[j] != NULL; j++) {\n        rofi_int_matcher *ftokens[2] = {tokens[j], NULL};\n        int test = 0;\n        test = helper_token_match(ftokens, esc);\n        if (test == tokens[j]->invert && rmpd->cmd_list[index].meta) {\n          test = helper_token_match(ftokens, rmpd->cmd_list[index].meta);\n        }\n\n        if (test == 0) {\n          match = 0;\n        }\n      }\n    }\n    if (rmpd->do_markup) {\n      g_free(esc);\n    }\n    return match;\n  }\n  return FALSE;\n}\nstatic char *script_get_message(const Mode *sw) {\n  ScriptModePrivateData *pd = sw->private_data;\n  return g_strdup(pd->message);\n}\nstatic cairo_surface_t *script_get_icon(const Mode *sw,\n                                        unsigned int selected_line,\n                                        unsigned int height) {\n  ScriptModePrivateData *pd =\n      (ScriptModePrivateData *)mode_get_private_data(sw);\n\n  const guint scale = display_scale();\n\n  g_return_val_if_fail(pd->cmd_list != NULL, NULL);\n  DmenuScriptEntry *dr = &(pd->cmd_list[selected_line]);\n  if (dr->icon_name == NULL) {\n    return NULL;\n  }\n\n  if (dr->icon_fetch_uid > 0) {\n    cairo_surface_t *surface = NULL;\n    gboolean query_done =\n        rofi_icon_fetcher_get_ex(dr->icon_fetch_uid, &surface);\n\n    if (surface != NULL) {\n      return surface;\n    } else if (query_done) {\n      dr->icon_fallback_index++;\n      dr->icon_fetch_uid = 0;\n    } else {\n      return NULL;\n    }\n  }\n\n  char *current_icon = NULL;\n  if (dr->icon_name && dr->icon_fallback_index >= 0) {\n    int icon_count = g_strv_length(dr->icon_name);\n    if (dr->icon_fallback_index < icon_count) {\n      current_icon = dr->icon_name[dr->icon_fallback_index];\n    }\n  }\n  if (current_icon) {\n    dr->icon_fetch_uid = rofi_icon_fetcher_query(current_icon, height);\n    dr->icon_fetch_size = height;\n    dr->icon_fetch_scale = scale;\n\n  } else {\n    dr->icon_fetch_uid = 0;\n  }\n\n  return NULL;\n}\n\n#include \"mode-private.h\"\n\n/** Structure that holds a user script\n * found in $config/rofi/scripts/\n */\ntypedef struct ScriptUser {\n  /** name of the script */\n  char *name;\n  /** path to the script. */\n  char *path;\n} ScriptUser;\n\n/** list of user_scripts. */\nScriptUser *user_scripts = NULL;\n/** number of user scripts collected */\nsize_t num_scripts = 0;\n\nvoid script_mode_cleanup(void) {\n  for (size_t i = 0; i < num_scripts; i++) {\n    g_free(user_scripts[i].name);\n    g_free(user_scripts[i].path);\n  }\n  g_free(user_scripts);\n}\nvoid script_mode_gather_user_scripts(void) {\n  const char *cpath = g_get_user_config_dir();\n  char *script_dir = g_build_filename(cpath, \"rofi\", \"scripts\", NULL);\n  if (g_file_test(script_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) ==\n      FALSE) {\n    g_free(script_dir);\n    return;\n  }\n  GDir *sd = g_dir_open(script_dir, 0, NULL);\n  if (sd) {\n    const char *file = NULL;\n    while ((file = g_dir_read_name(sd)) != NULL) {\n      char *sp = g_build_filename(cpath, \"rofi\", \"scripts\", file, NULL);\n      user_scripts =\n          g_realloc(user_scripts, sizeof(ScriptUser) * (num_scripts + 1));\n      user_scripts[num_scripts].path = sp;\n      user_scripts[num_scripts].name = g_strdup(file);\n      char *dot = strrchr(user_scripts[num_scripts].name, '.');\n      if (dot) {\n        *dot = '\\0';\n      }\n      num_scripts++;\n    }\n    g_dir_close(sd);\n  }\n\n  g_free(script_dir);\n}\n\nstatic int script_mode_has_user_script(char const *const user) {\n\n  for (size_t i = 0; i < num_scripts; i++) {\n    if (g_strcmp0(user_scripts[i].name, user) == 0) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nMode *script_mode_parse_setup(const char *str) {\n  int ui = 0;\n  if ((ui = script_mode_has_user_script(str)) >= 0) {\n    Mode *sw = g_malloc0(sizeof(*sw));\n    sw->name = g_strdup(user_scripts[ui].name);\n    sw->ed = g_strdup(user_scripts[ui].path);\n    sw->free = script_switcher_free;\n    sw->_init = script_mode_init;\n    sw->_get_num_entries = script_mode_get_num_entries;\n    sw->_result = script_mode_result;\n    sw->_destroy = script_mode_destroy;\n    sw->_token_match = script_token_match;\n    sw->_get_message = script_get_message;\n    sw->_get_icon = script_get_icon;\n    sw->_get_completion = NULL, sw->_preprocess_input = NULL,\n    sw->_get_display_value = _get_display_value;\n    sw->type = MODE_TYPE_SWITCHER;\n    return sw;\n  }\n  Mode *sw = g_malloc0(sizeof(*sw));\n  unsigned int index = 0;\n  const char *const sep = \":\";\n  char **tokens = g_strsplit(str, sep, 2);\n  if (tokens) {\n    index = g_strv_length(tokens);\n    sw->name = g_strdup(tokens[0]);\n    sw->ed = (void *)rofi_expand_path(tokens[1]);\n    g_strfreev(tokens);\n  }\n  if (index == 2) {\n    sw->free = script_switcher_free;\n    sw->_init = script_mode_init;\n    sw->_get_num_entries = script_mode_get_num_entries;\n    sw->_result = script_mode_result;\n    sw->_destroy = script_mode_destroy;\n    sw->_token_match = script_token_match;\n    sw->_get_message = script_get_message;\n    sw->_get_icon = script_get_icon;\n    sw->_get_completion = NULL, sw->_preprocess_input = NULL,\n    sw->_get_display_value = _get_display_value;\n    sw->type = MODE_TYPE_SWITCHER;\n\n    return sw;\n  }\n  fprintf(\n      stderr,\n      \"The script command '%s' has %u options, but needs 2: <name>:<script>.\",\n      str, index);\n  script_switcher_free(sw);\n  return NULL;\n}\n\ngboolean script_mode_is_valid(const char *token) {\n  if (script_mode_has_user_script(token) >= 0) {\n    return TRUE;\n  }\n  return strchr(token, ':') != NULL;\n}\n\nvoid script_user_list(gboolean is_term) {\n\n  for (unsigned int i = 0; i < num_scripts; i++) {\n    printf(\"        • %s%s%s (%s)\\n\", is_term ? (color_bold) : \"\",\n           user_scripts[i].name, is_term ? color_reset : \"\",\n           user_scripts[i].path);\n  }\n}\n"
  },
  {
    "path": "source/modes/ssh.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/**\n * \\ingroup SSHMode\n * @{\n */\n\n/**\n * Log domain for the ssh mode.\n */\n#define G_LOG_DOMAIN \"Modes.Ssh\"\n\n#include \"config.h\"\n#include <glib.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <ctype.h>\n#include <dirent.h>\n#include <errno.h>\n#include <glob.h>\n#include <helper.h>\n#include <signal.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"history.h\"\n#include \"modes/ssh.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n\n/**\n * Holding an ssh entry.\n */\ntypedef struct _SshEntry {\n  /** SSH hostname */\n  char *hostname;\n  char **aliases;\n  /** SSH port number */\n  int port;\n} SshEntry;\n/**\n * The internal data structure holding the private data of the SSH Mode.\n */\ntypedef struct {\n  GList *user_known_hosts;\n  /** List if available ssh hosts.*/\n  SshEntry *hosts_list;\n  /** Length of the #hosts_list.*/\n  unsigned int hosts_list_length;\n} SSHModePrivateData;\n\n/**\n * Name of the history file where previously chosen hosts are stored.\n */\n#define SSH_CACHE_FILE \"rofi-2.sshcache\"\n\n/**\n * Used in get_ssh() when splitting lines from the user's\n * SSH config file into tokens.\n */\n#define SSH_TOKEN_DELIM \"= \\t\\r\\n\"\n\n/**\n * @param entry The host to connect too\n *\n * SSH into the selected host.\n *\n * @returns FALSE On failure, TRUE on success\n */\nstatic int execshssh(const SshEntry *entry) {\n  char **args = NULL;\n  int argsv = 0;\n  gchar *portstr = NULL;\n  if (entry->port > 0) {\n    portstr = g_strdup_printf(\"%d\", entry->port);\n  }\n  helper_parse_setup(config.ssh_command, &args, &argsv, \"{host}\",\n                     entry->hostname, \"{port}\", portstr, (char *)0);\n  g_free(portstr);\n\n  gsize l = strlen(\"Connecting to '' via rofi\") + strlen(entry->hostname) + 1;\n  gchar *desc = g_newa(gchar, l);\n\n  g_snprintf(desc, l, \"Connecting to '%s' via rofi\", entry->hostname);\n\n  RofiHelperExecuteContext context = {\n      .name = \"ssh\",\n      .description = desc,\n      .command = \"ssh\",\n  };\n  return helper_execute(NULL, args, \"ssh \", entry->hostname, &context);\n}\n\n/**\n * @param entry The host to connect too\n *\n * SSH into the selected host, if successful update history.\n */\nstatic void exec_ssh(const SshEntry *entry) {\n  if (!(entry->hostname) || !(entry->hostname[0])) {\n    return;\n  }\n\n  if (!execshssh(entry)) {\n    return;\n  }\n\n  //  This happens in non-critical time (After launching app)\n  //  It is allowed to be a bit slower.\n  char *path = g_build_filename(cache_dir, SSH_CACHE_FILE, NULL);\n  // TODO update.\n  GString *str = g_string_new(entry->hostname);\n  g_string_append_printf(str, \"\\x1F%d\", entry->port);\n  for (int x = 0; entry->aliases && entry->aliases[x]; x++) {\n    g_string_append_printf(str, \"\\x1F%s\", entry->aliases[x]);\n  }\n  history_set(path, str->str);\n  g_string_free(str, TRUE);\n  g_free(path);\n}\n\n/**\n * @param host The host to remove from history\n *\n * Remove host from history.\n */\nstatic void delete_ssh(const char *host) {\n  if (!host || !host[0]) {\n    return;\n  }\n  char *path = g_build_filename(cache_dir, SSH_CACHE_FILE, NULL);\n  history_remove(path, host);\n  g_free(path);\n}\n\n/**\n * @param path Path of the known host file.\n * @param retv list of hosts\n * @param length pointer to length of list [in][out]\n *\n * Read 'known_hosts' file when entries are not hashed.\n *\n * @returns updated list of hosts.\n */\nstatic SshEntry *read_known_hosts_file(const char *path, SshEntry *retv,\n                                       unsigned int *length) {\n  FILE *fd = fopen(path, \"r\");\n  if (fd != NULL) {\n    char *buffer = NULL;\n    size_t buffer_length = 0;\n    // Reading one line per time.\n    while (getline(&buffer, &buffer_length, fd) > 0) {\n      // Strip whitespace.\n      char *start = g_strstrip(&(buffer[0]));\n      // Find start.\n      if (*start == '#' || *start == '@') {\n        // skip comments or cert-authority or revoked items.\n        continue;\n      }\n      if (*start == '|') {\n        // Skip hashed hostnames.\n        continue;\n      }\n      // Find end of hostname set.\n      char *end = strstr(start, \" \");\n      if (end == NULL) {\n        // Something is wrong.\n        continue;\n      }\n      *end = '\\0';\n      char *sep = start;\n      start = strsep(&sep, \", \");\n      while (start) {\n        int port = 0;\n        if (start[0] == '[') {\n          start++;\n          char *strend = strchr(start, ']');\n          if (strend[1] == ':') {\n            *strend = '\\0';\n            errno = 0;\n            gchar *endptr = NULL;\n            gint64 number = g_ascii_strtoll(&(strend[2]), &endptr, 10);\n            if (errno != 0) {\n              g_warning(\"Failed to parse port number: %s.\", &(strend[2]));\n            } else if (endptr == &(strend[2])) {\n              g_warning(\"Failed to parse port number: %s, invalid number.\",\n                        &(strend[2]));\n            } else if (number < 0 || number > 65535) {\n              g_warning(\"Failed to parse port number: %s, out of range.\",\n                        &(strend[2]));\n            } else {\n              port = number;\n            }\n          }\n        }\n        // Is this host name already in the list?\n        // We often get duplicates in hosts file, so lets check this.\n        int found = 0;\n        for (unsigned int j = 0; j < (*length); j++) {\n          if (!g_ascii_strcasecmp(start, retv[j].hostname)) {\n            found = 1;\n            break;\n          }\n        }\n\n        if (!found) {\n          // Add this host name to the list.\n          retv = g_realloc(retv, ((*length) + 2) * sizeof(SshEntry));\n          retv[(*length)].hostname = g_strdup(start);\n          retv[(*length)].aliases = NULL;\n          retv[(*length)].port = port;\n          retv[(*length) + 1].hostname = NULL;\n          retv[(*length) + 1].aliases = NULL;\n          retv[(*length) + 1].port = 0;\n          (*length)++;\n        }\n        start = strsep(&sep, \", \");\n      }\n    }\n    if (buffer != NULL) {\n      free(buffer);\n    }\n    if (fclose(fd) != 0) {\n      g_warning(\"Failed to close hosts file: '%s'\", g_strerror(errno));\n    }\n  } else {\n    g_debug(\"Failed to open KnownHostFile: '%s'\", path);\n  }\n\n  return retv;\n}\n\n/**\n * @param retv The list of hosts to update.\n * @param length The length of the list retv [in][out]\n *\n * Read `/etc/hosts` and appends them to the list retv\n *\n * @returns an updated list with the added hosts.\n */\nstatic SshEntry *read_hosts_file(SshEntry *retv, unsigned int *length) {\n  // Read the hosts file.\n  FILE *fd = fopen(\"/etc/hosts\", \"r\");\n  if (fd != NULL) {\n    char *buffer = NULL;\n    size_t buffer_length = 0;\n    // Reading one line per time.\n    while (getline(&buffer, &buffer_length, fd) > 0) {\n      // Evaluate one line.\n      unsigned int index = 0, ti = 0;\n      char *token = buffer;\n\n      // Tokenize it.\n      do {\n        char c = buffer[index];\n        // Break on space, tab, newline and \\0.\n        if (c == ' ' || c == '\\t' || c == '\\n' || c == '\\0' || c == '#') {\n          buffer[index] = '\\0';\n          // Ignore empty tokens\n          if (token[0] != '\\0') {\n            ti++;\n            // and first token.\n            if (ti > 1) {\n              // Is this host name already in the list?\n              // We often get duplicates in hosts file, so lets check this.\n              int found = 0;\n              for (unsigned int j = 0; j < (*length); j++) {\n                if (!g_ascii_strcasecmp(token, retv[j].hostname)) {\n                  found = 1;\n                  break;\n                }\n              }\n\n              if (!found) {\n                // Add this host name to the list.\n                retv = g_realloc(retv, ((*length) + 2) * sizeof(SshEntry));\n                retv[(*length)].hostname = g_strdup(token);\n                retv[(*length)].aliases = NULL;\n                retv[(*length)].port = 0;\n                retv[(*length) + 1].hostname = NULL;\n                retv[(*length) + 1].aliases = NULL;\n                (*length)++;\n              }\n            }\n          }\n          // Set start to next element.\n          token = &buffer[index + 1];\n          // Everything after comment ignore.\n          if (c == '#') {\n            break;\n          }\n        }\n        // Skip to the next entry.\n        index++;\n      } while (buffer[index] != '\\0' && buffer[index] != '#');\n    }\n    if (buffer != NULL) {\n      free(buffer);\n    }\n    if (fclose(fd) != 0) {\n      g_warning(\"Failed to close hosts file: '%s'\", g_strerror(errno));\n    }\n  }\n\n  return retv;\n}\n\nstatic void add_known_hosts_file(SSHModePrivateData *pd, const char *token) {\n  GList *item =\n      g_list_find_custom(pd->user_known_hosts, token, (GCompareFunc)g_strcmp0);\n  if (item == NULL) {\n    g_debug(\"Add '%s' to UserKnownHost list\", token);\n    pd->user_known_hosts = g_list_append(pd->user_known_hosts, g_strdup(token));\n  } else {\n    g_debug(\"File '%s' already in UserKnownHostsFile list\", token);\n  }\n}\n\nstatic void parse_ssh_config_file(SSHModePrivateData *pd, const char *filename,\n                                  SshEntry **retv, unsigned int *length,\n                                  unsigned int num_favorites) {\n  FILE *fd = fopen(filename, \"r\");\n\n  g_debug(\"Parsing ssh config file: %s\", filename);\n  if (fd != NULL) {\n    char *buffer = NULL;\n    size_t buffer_length = 0;\n    char *strtok_pointer = NULL;\n    while (getline(&buffer, &buffer_length, fd) > 0) {\n      // Each line is either empty, a comment line starting with a '#'\n      // character or of the form \"keyword [=] arguments\", where there may\n      // be multiple (possibly quoted) arguments separated by whitespace.\n      // The keyword is separated from its arguments by whitespace OR by\n      // optional whitespace and a '=' character.\n      char *token = strtok_r(buffer, SSH_TOKEN_DELIM, &strtok_pointer);\n      // Skip empty lines and comment lines. Also skip lines where the\n      // keyword is not \"Host\".\n      if (!token || *token == '#') {\n        continue;\n      }\n      char *low_token = g_ascii_strdown(token, -1);\n      if (g_strcmp0(low_token, \"include\") == 0) {\n        token = strtok_r(NULL, SSH_TOKEN_DELIM, &strtok_pointer);\n        g_debug(\"Found Include: %s\", token);\n        gchar *path = rofi_expand_path(token);\n        gchar *full_path = NULL;\n        if (!g_path_is_absolute(path)) {\n          char *dirname = g_path_get_dirname(filename);\n          full_path = g_build_filename(dirname, path, NULL);\n          g_free(dirname);\n        } else {\n          full_path = g_strdup(path);\n        }\n        glob_t globbuf = {.gl_pathc = 0, .gl_pathv = NULL, .gl_offs = 0};\n\n        if (glob(full_path, 0, NULL, &globbuf) == 0) {\n          for (size_t iter = 0; iter < globbuf.gl_pathc; iter++) {\n            parse_ssh_config_file(pd, globbuf.gl_pathv[iter], retv, length,\n                                  num_favorites);\n          }\n        }\n        globfree(&globbuf);\n\n        g_free(full_path);\n        g_free(path);\n      } else if (g_strcmp0(low_token, \"userknownhostsfile\") == 0) {\n        while ((token = strtok_r(NULL, SSH_TOKEN_DELIM, &strtok_pointer))) {\n          g_debug(\"Found extra UserKnownHostsFile: %s\", token);\n          add_known_hosts_file(pd, token);\n        }\n      } else if (g_strcmp0(low_token, \"host\") == 0) {\n        // Now we know that this is a \"Host\" line.\n        // The \"Host\" keyword is followed by one more host names separated\n        // by whitespace; while host names may be quoted with double quotes\n        // to represent host names containing spaces, we don't support this\n        // (how many host names contain spaces?).\n        int aliases = 0;\n        while ((token = strtok_r(NULL, SSH_TOKEN_DELIM, &strtok_pointer))) {\n          // We do not want to show wildcard entries, as you cannot ssh to them.\n          const char *const sep = \"*?\";\n          if (*token == '!' || strpbrk(token, sep)) {\n            continue;\n          }\n\n          // If comment, skip from now on.\n          if (*token == '#') {\n            break;\n          }\n\n          // Is this host name already in the history file?\n          // This is a nice little penalty, but doable? time will tell.\n          // given num_favorites is max 25.\n          int found = 0;\n          for (unsigned int j = 0; j < num_favorites; j++) {\n            if (!g_ascii_strcasecmp(token, (*retv)[j].hostname)) {\n              found = 1;\n              break;\n            }\n            if ((*retv)[j].aliases != NULL) {\n              for (int x = 0; (*retv)[j].aliases[x] != NULL; x++) {\n                if (!g_ascii_strcasecmp(token, (*retv)[j].aliases[x])) {\n                  found = 1;\n                  break;\n                }\n              }\n            }\n          }\n\n          if (found) {\n            continue;\n          }\n\n          if (aliases == 0) {\n            // Add this host name to the list.\n            (*retv) = g_realloc((*retv), ((*length) + 2) * sizeof(SshEntry));\n            (*retv)[(*length)].hostname = g_strdup(token);\n            (*retv)[(*length)].aliases = NULL;\n            (*retv)[(*length)].port = 0;\n            (*retv)[(*length) + 1].hostname = NULL;\n            (*retv)[(*length) + 1].aliases = NULL;\n            (*length)++;\n            aliases = 1;\n          } else {\n            int index = (*length) - 1;\n            int l = 0;\n            if ((*retv)[index].aliases != NULL) {\n              l = g_strv_length((*retv)[index].aliases);\n            }\n            (*retv)[index].aliases =\n                g_realloc((*retv)[index].aliases, (l + 2) * sizeof(char *));\n            (*retv)[index].aliases[l] = g_strdup(token);\n            (*retv)[index].aliases[l + 1] = NULL;\n          }\n        }\n      }\n      g_free(low_token);\n    }\n    if (buffer != NULL) {\n      free(buffer);\n    }\n\n    if (fclose(fd) != 0) {\n      g_warning(\"Failed to close ssh configuration file: '%s'\",\n                g_strerror(errno));\n    }\n  }\n}\n\n/**\n * @param pd The plugin data handle\n * @param length The number of found ssh hosts [out]\n *\n * Gets the list available SSH hosts.\n *\n * @returns an array of strings containing all the hosts.\n */\nstatic SshEntry *get_ssh(SSHModePrivateData *pd, unsigned int *length) {\n  SshEntry *retv = NULL;\n  unsigned int num_favorites = 0;\n  char *path;\n\n  if (g_get_home_dir() == NULL) {\n    return NULL;\n  }\n\n  path = g_build_filename(cache_dir, SSH_CACHE_FILE, NULL);\n  char **h = history_get_list(path, length);\n\n  retv = malloc((*length) * sizeof(SshEntry));\n  for (unsigned int i = 0; i < (*length); i++) {\n    int port = 0;\n    char **ssplit = g_strsplit(h[i], \"\\x1F\", -1);\n    guint ssplit_len = g_strv_length(ssplit);\n    if (ssplit_len > 1) {\n      errno = 0;\n      gchar *endptr = NULL;\n      gint64 number = g_ascii_strtoll(ssplit[1], &endptr, 10);\n      if (errno != 0) {\n        g_warning(\"Failed to parse port number: %s.\", (ssplit[1]));\n      } else if (endptr == (ssplit[1])) {\n        g_warning(\"Failed to parse port number: %s, invalid number.\",\n                  (ssplit[1]));\n      } else if (number < 0 || number > 65535) {\n        g_warning(\"Failed to parse port number: %s, out of range.\",\n                  (ssplit[1]));\n      } else {\n        port = number;\n      }\n    }\n    retv[i].hostname = g_strdup(ssplit[0]);\n    retv[i].port = port;\n    retv[i].aliases = NULL;\n    gint naliases = ssplit_len - 2;\n    if (naliases > 0) {\n      retv[i].aliases = g_malloc0(sizeof(char *) * (naliases + 1));\n      for (gint j = 0; j < naliases; j++) {\n        retv[i].aliases[j] = g_strdup(ssplit[2 + j]);\n      }\n    }\n    g_strfreev(ssplit);\n  }\n  g_free(h);\n\n  g_free(path);\n  num_favorites = (*length);\n\n  const char *hd = g_get_home_dir();\n  path = g_build_filename(hd, \".ssh\", \"config\", NULL);\n  parse_ssh_config_file(pd, path, &retv, length, num_favorites);\n\n  if (config.parse_known_hosts == TRUE) {\n    char *known_hosts_path =\n        g_build_filename(g_get_home_dir(), \".ssh\", \"known_hosts\", NULL);\n    retv = read_known_hosts_file(known_hosts_path, retv, length);\n    g_free(known_hosts_path);\n    for (GList *iter = g_list_first(pd->user_known_hosts); iter;\n         iter = g_list_next(iter)) {\n      char *user_known_hosts_path = rofi_expand_path((const char *)iter->data);\n      retv = read_known_hosts_file((const char *)user_known_hosts_path, retv,\n                                   length);\n      g_free(user_known_hosts_path);\n    }\n  }\n  if (config.parse_hosts == TRUE) {\n    retv = read_hosts_file(retv, length);\n  }\n\n  g_free(path);\n\n  return retv;\n}\n\n/**\n * @param sw Object handle to the SSH Mode object\n *\n * Initializes the SSH Mode private data object and\n * loads the relevant ssh information.\n */\nstatic int ssh_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n    SSHModePrivateData *pd = g_malloc0(sizeof(*pd));\n    mode_set_private_data(sw, (void *)pd);\n    pd->hosts_list = get_ssh(pd, &(pd->hosts_list_length));\n  }\n  return TRUE;\n}\n\n/**\n * @param sw Object handle to the SSH Mode object\n *\n * Get the number of SSH entries.\n *\n * @returns the number of ssh entries.\n */\nstatic unsigned int ssh_mode_get_num_entries(const Mode *sw) {\n  const SSHModePrivateData *rmpd =\n      (const SSHModePrivateData *)mode_get_private_data(sw);\n  return rmpd->hosts_list_length;\n}\n/**\n * @param sw Object handle to the SSH Mode object\n *\n * Cleanup the SSH Mode. Free all allocated memory and NULL the private data\n * pointer.\n */\nstatic void ssh_mode_destroy(Mode *sw) {\n  SSHModePrivateData *rmpd = (SSHModePrivateData *)mode_get_private_data(sw);\n  if (rmpd != NULL) {\n    for (unsigned int i = 0; i < rmpd->hosts_list_length; i++) {\n      g_free(rmpd->hosts_list[i].hostname);\n      g_strfreev(rmpd->hosts_list[i].aliases);\n    }\n    g_list_free_full(rmpd->user_known_hosts, g_free);\n    g_free(rmpd->hosts_list);\n    g_free(rmpd);\n    mode_set_private_data(sw, NULL);\n  }\n}\n\n/**\n * @param sw Object handle to the SSH Mode object\n * @param mretv The menu return value.\n * @param input Pointer to the user input string.\n * @param selected_line the line selected by the user.\n *\n * Acts on the user interaction.\n *\n * @returns the next #ModeMode.\n */\nstatic ModeMode ssh_mode_result(Mode *sw, int mretv, char **input,\n                                unsigned int selected_line) {\n  ModeMode retv = MODE_EXIT;\n  SSHModePrivateData *rmpd = (SSHModePrivateData *)mode_get_private_data(sw);\n  if ((mretv & MENU_OK) && rmpd->hosts_list[selected_line].hostname != NULL) {\n    exec_ssh(&(rmpd->hosts_list[selected_line]));\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&\n             *input[0] != '\\0') {\n    SshEntry entry = {.hostname = *input, .port = 0};\n    exec_ssh(&entry);\n  } else if ((mretv & MENU_ENTRY_DELETE) &&\n             rmpd->hosts_list[selected_line].hostname) {\n    delete_ssh(rmpd->hosts_list[selected_line].hostname);\n    // Stay\n    retv = RELOAD_DIALOG;\n    ssh_mode_destroy(sw);\n    ssh_mode_init(sw);\n  } else if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  }\n  return retv;\n}\n\n/**\n * @param sw Object handle to the SSH Mode object\n * @param selected_line The line to view\n * @param state The state of the entry [out]\n * @param attr_list List of extra rendering attributes to set [out]\n * @param get_entry\n *\n * Gets the string as it should be displayed and the display state.\n * If get_entry is FALSE only the state is set.\n *\n * @return the string as it should be displayed and the display state.\n */\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                G_GNUC_UNUSED int *state,\n                                G_GNUC_UNUSED GList **attr_list,\n                                int get_entry) {\n  SSHModePrivateData *rmpd = (SSHModePrivateData *)mode_get_private_data(sw);\n  if (get_entry) {\n    GString *str = g_string_new(rmpd->hosts_list[selected_line].hostname);\n\n    if (rmpd->hosts_list[selected_line].aliases) {\n      g_string_append(str, \" (\");\n      for (int i = 0; rmpd->hosts_list[selected_line].aliases[i]; i++) {\n        g_string_append_printf(str, \" %s\",\n                               rmpd->hosts_list[selected_line].aliases[i]);\n        if (rmpd->hosts_list[selected_line].aliases[i + 1] != NULL) {\n          g_string_append(str, \",\");\n        }\n      }\n      g_string_append(str, \" )\");\n    }\n\n    char *cstr = str->str;\n    g_string_free(str, FALSE);\n    return cstr;\n  }\n\n  return NULL;\n}\n\n/**\n * @param sw Object handle to the SSH Mode object\n * @param tokens The set of tokens to match against\n * @param index The index of the entry to match\n *\n * Match entry against the set of tokens.\n *\n * @returns TRUE if matches\n */\nstatic int ssh_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                           unsigned int index) {\n  SSHModePrivateData *rmpd = (SSHModePrivateData *)mode_get_private_data(sw);\n  int s = helper_token_match(tokens, rmpd->hosts_list[index].hostname);\n  for (int i = 0;\n       rmpd->hosts_list[index].aliases && rmpd->hosts_list[index].aliases[i];\n       i++) {\n    s |= helper_token_match(tokens, rmpd->hosts_list[index].aliases[i]);\n  }\n  return s;\n}\n#include \"mode-private.h\"\nMode ssh_mode = {.name = \"ssh\",\n                 .cfg_name_key = \"display-ssh\",\n                 ._init = ssh_mode_init,\n                 ._get_num_entries = ssh_mode_get_num_entries,\n                 ._result = ssh_mode_result,\n                 ._destroy = ssh_mode_destroy,\n                 ._token_match = ssh_token_match,\n                 ._get_display_value = _get_display_value,\n                 ._get_completion = NULL,\n                 ._preprocess_input = NULL,\n                 .private_data = NULL,\n                 .free = NULL,\n                 .type = MODE_TYPE_SWITCHER};\n/**@}*/\n"
  },
  {
    "path": "source/modes/wayland-window.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2022 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this dialog. */\n#define G_LOG_DOMAIN \"Modes.Window\"\n\n#include \"config.h\"\n\n#ifdef WINDOW_MODE\n\n#include <stdint.h>\n\n#include <glib.h>\n#include <wayland-client.h>\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"modes/wayland-window.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"wayland-internal.h\"\n#include \"widgets/textbox.h\"\n\n#include \"mode-private.h\"\n#include \"rofi-icon-fetcher.h\"\n\n#include \"wlr-foreign-toplevel-management-unstable-v1-protocol.h\"\n\n#define WLR_FOREIGN_TOPLEVEL_VERSION 3\n\nenum WaylandWindowMatchingFields {\n  WW_MATCH_FIELD_TITLE = 1 << 0,\n  WW_MATCH_FIELD_APP_ID = 1 << 1,\n  WW_MATCH_FIELD_ALL = ~0,\n};\n\ntypedef struct _WaylandWindowModePrivateData {\n  wayland_stuff *wayland;\n  struct wl_registry *registry;\n  struct zwlr_foreign_toplevel_manager_v1 *manager;\n  GList *toplevels; /* List of ForeignToplevelHandle */\n\n  /* initial rendering complete, updates allowed */\n  gboolean visible;\n  int match_fields; /* bitmask of WaylandWindowMatchingFields */\n  glong title_len;\n  glong app_id_len;\n  GRegex *window_regex;\n} WaylandWindowModePrivateData;\n\nenum ForeignToplevelState {\n  TOPLEVEL_STATE_MAXIMIZED = 1\n                             << ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED,\n  TOPLEVEL_STATE_MINIMIZED = 1\n                             << ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED,\n  TOPLEVEL_STATE_ACTIVATED = 1\n                             << ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED,\n  TOPLEVEL_STATE_FULLSCREEN =\n      1 << ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN,\n  TOPLEVEL_STATE_CLOSED = 1 << 4\n};\n\ntypedef struct {\n  struct zwlr_foreign_toplevel_handle_v1 *handle;\n  WaylandWindowModePrivateData *view;\n\n  gchar *app_id;\n  glong app_id_len;\n  gchar *title;\n  glong title_len;\n  int state;\n\n  unsigned int cached_icon_uid;\n  unsigned int cached_icon_size;\n  guint cached_icon_scale;\n} ForeignToplevelHandle;\n\nstatic void foreign_toplevel_handle_free(ForeignToplevelHandle *self) {\n\n  if (self->handle) {\n    zwlr_foreign_toplevel_handle_v1_destroy(self->handle);\n    self->handle = NULL;\n  }\n  g_free(self->title);\n  g_free(self->app_id);\n  g_free(self);\n}\n\nstatic void toplevels_list_update_max_len(gpointer data, gpointer user_data) {\n  WaylandWindowModePrivateData *pd = (WaylandWindowModePrivateData *)user_data;\n  ForeignToplevelHandle *entry = (ForeignToplevelHandle *)data;\n\n  pd->title_len = MAX(entry->title_len, pd->title_len);\n  pd->app_id_len = MAX(entry->app_id_len, pd->app_id_len);\n}\n\n/* Update column alignment and schedule reload */\nstatic void wayland_window_update_toplevel(ForeignToplevelHandle *toplevel) {\n  WaylandWindowModePrivateData *pd = toplevel->view;\n\n  if (!pd->visible) {\n    /* initial fetch, just add the current item */\n    toplevels_list_update_max_len(toplevel, pd);\n  } else {\n    /* async update, recalculate from scratch */\n    pd->title_len = 0;\n    pd->app_id_len = 0;\n    g_list_foreach(pd->toplevels, toplevels_list_update_max_len, pd);\n    rofi_view_reload();\n  }\n}\n\n/* requests */\n\nstatic void foreign_toplevel_handle_activate(ForeignToplevelHandle *self,\n                                             struct wl_seat *seat) {\n  zwlr_foreign_toplevel_handle_v1_activate(self->handle, seat);\n}\n\nstatic void foreign_toplevel_handle_close(ForeignToplevelHandle *self) {\n  zwlr_foreign_toplevel_handle_v1_close(self->handle);\n}\n\n/* events */\n\nstatic void foreign_toplevel_handle_title(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    const char *title) {\n  ForeignToplevelHandle *self = (ForeignToplevelHandle *)data;\n  if (self->title) {\n    g_free(self->title);\n  }\n  self->title = g_strdup(title);\n  self->title_len = g_utf8_strlen(self->title, -1);\n}\n\nstatic void foreign_toplevel_handle_app_id(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    const char *app_id) {\n  ForeignToplevelHandle *self = (ForeignToplevelHandle *)data;\n  if (self->app_id) {\n    g_free(self->app_id);\n  }\n  self->app_id = g_strdup(app_id);\n  self->app_id_len = g_utf8_strlen(self->app_id, -1);\n}\n\nstatic void foreign_toplevel_handle_output_enter(\n    G_GNUC_UNUSED void *data,\n    G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    G_GNUC_UNUSED struct wl_output *output) {\n  /* ignore */\n}\n\nstatic void foreign_toplevel_handle_output_leave(\n    G_GNUC_UNUSED void *data,\n    G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    G_GNUC_UNUSED struct wl_output *output) {\n  /* ignore */\n}\n\nstatic void foreign_toplevel_handle_state(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    struct wl_array *value) {\n  ForeignToplevelHandle *self = (ForeignToplevelHandle *)data;\n  uint32_t *elem;\n\n  self->state = 0;\n  wl_array_for_each(elem, value) { self->state |= 1 << *elem; }\n}\n\nstatic void foreign_toplevel_handle_done(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle) {\n  ForeignToplevelHandle *self = (ForeignToplevelHandle *)data;\n\n  g_debug(\"window %p id=%s title=%s state=%d\\n\", (void *)self, self->app_id,\n          self->title, self->state);\n\n  wayland_window_update_toplevel(self);\n}\n\nstatic void foreign_toplevel_handle_closed(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle) {\n  ForeignToplevelHandle *self = (ForeignToplevelHandle *)data;\n\n  /* the handle is inert and will receive no further events */\n  self->state = TOPLEVEL_STATE_CLOSED;\n  self->view->toplevels = g_list_remove(self->view->toplevels, self);\n  wayland_window_update_toplevel(self);\n  foreign_toplevel_handle_free(self);\n}\n\nstatic void foreign_toplevel_handle_parent(\n    G_GNUC_UNUSED void *data,\n    G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *handle,\n    G_GNUC_UNUSED struct zwlr_foreign_toplevel_handle_v1 *parent) {\n  /* ignore */\n}\n\nstatic struct zwlr_foreign_toplevel_handle_v1_listener\n    foreign_toplevel_handle_listener = {\n        .title = &foreign_toplevel_handle_title,\n        .app_id = &foreign_toplevel_handle_app_id,\n        .output_enter = &foreign_toplevel_handle_output_enter,\n        .output_leave = &foreign_toplevel_handle_output_leave,\n        .state = &foreign_toplevel_handle_state,\n        .done = &foreign_toplevel_handle_done,\n        .closed = &foreign_toplevel_handle_closed,\n        .parent = &foreign_toplevel_handle_parent};\n\nstatic ForeignToplevelHandle *\nforeign_toplevel_handle_new(struct zwlr_foreign_toplevel_handle_v1 *handle,\n                            WaylandWindowModePrivateData *view) {\n  ForeignToplevelHandle *self =\n      (ForeignToplevelHandle *)g_malloc0(sizeof(ForeignToplevelHandle));\n\n  self->handle = handle;\n  self->view = view;\n  zwlr_foreign_toplevel_handle_v1_add_listener(\n      handle, &foreign_toplevel_handle_listener, self);\n  return self;\n}\n\nstatic void foreign_toplevel_manager_toplevel(\n    void *data, G_GNUC_UNUSED struct zwlr_foreign_toplevel_manager_v1 *manager,\n    struct zwlr_foreign_toplevel_handle_v1 *toplevel) {\n  WaylandWindowModePrivateData *pd = (WaylandWindowModePrivateData *)data;\n\n  ForeignToplevelHandle *handle = foreign_toplevel_handle_new(toplevel, pd);\n  pd->toplevels = g_list_prepend(pd->toplevels, handle);\n}\n\nstatic void foreign_toplevel_manager_finished(\n    G_GNUC_UNUSED void *data,\n    struct zwlr_foreign_toplevel_manager_v1 *manager) {\n  zwlr_foreign_toplevel_manager_v1_destroy(manager);\n}\n\nstatic struct zwlr_foreign_toplevel_manager_v1_listener\n    foreign_toplevel_manager_listener = {\n        .toplevel = &foreign_toplevel_manager_toplevel,\n        .finished = &foreign_toplevel_manager_finished};\n\nstatic void handle_global(void *data, struct wl_registry *registry,\n                          uint32_t name, const char *interface,\n                          uint32_t version) {\n  WaylandWindowModePrivateData *pd = (WaylandWindowModePrivateData *)data;\n\n  if (g_strcmp0(interface, zwlr_foreign_toplevel_manager_v1_interface.name) ==\n      0) {\n\n    pd->manager = (struct zwlr_foreign_toplevel_manager_v1 *)wl_registry_bind(\n        registry, name, &zwlr_foreign_toplevel_manager_v1_interface,\n        MIN(version, WLR_FOREIGN_TOPLEVEL_VERSION));\n  }\n}\n\nstatic void handle_global_remove(G_GNUC_UNUSED void *data,\n                                 G_GNUC_UNUSED struct wl_registry *registry,\n                                 G_GNUC_UNUSED uint32_t name) {}\n\nstatic struct wl_registry_listener registry_listener = {\n    .global = &handle_global, .global_remove = &handle_global_remove};\n\nstatic int wayland_window_mode_parse_fields(void) {\n  int result = 0;\n  char *savept = NULL;\n  // Make a copy, as strtok will modify it.\n  char *switcher_str = g_strdup(config.window_match_fields);\n\n  const char *const sep = \",#\";\n  for (char *token = strtok_r(switcher_str, sep, &savept); token != NULL;\n       token = strtok_r(NULL, sep, &savept)) {\n    if (g_strcmp0(token, \"all\") == 0) {\n      result |= WW_MATCH_FIELD_ALL;\n\n    } else if (g_strcmp0(token, \"title\") == 0) {\n      result |= WW_MATCH_FIELD_TITLE;\n\n    } else if (g_strcmp0(token, \"class\") == 0 ||\n               g_strcmp0(token, \"app-id\") == 0) {\n      result |= WW_MATCH_FIELD_APP_ID;\n\n    } else {\n      g_warning(\"Unsupported window field name :%s. \"\n                \"Wayland window switcher supports only 'title' and 'app-id' \"\n                \"('class') fields\",\n                token);\n    }\n  }\n  g_free(switcher_str);\n  return result;\n}\n\nstatic void get_wayland_window(Mode *sw) {\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n\n  pd->match_fields = wayland_window_mode_parse_fields();\n  pd->window_regex = g_regex_new(\"{[-\\\\w]+(:-?[0-9]+)?}\", 0, 0, NULL);\n\n  pd->wayland = wayland;\n\n  pd->registry = wl_display_get_registry(wayland->display);\n  wl_registry_add_listener(pd->registry, &registry_listener, pd);\n  wl_display_roundtrip(wayland->display);\n\n  if (pd->manager == NULL) {\n    g_warning(\"Unable to initialize Window mode: Wayland compositor does not \"\n              \"support wlr-foreign-toplevel-management protocol\");\n    return;\n  }\n\n  zwlr_foreign_toplevel_manager_v1_add_listener(\n      pd->manager, &foreign_toplevel_manager_listener, pd);\n  /* fetch initial set of windows */\n  wl_display_roundtrip(wayland->display);\n  pd->visible = TRUE;\n}\n\nstatic void toplevels_list_item_free(gpointer data,\n                                     G_GNUC_UNUSED gpointer user_data) {\n  foreign_toplevel_handle_free((ForeignToplevelHandle *)data);\n}\n\nstatic void wayland_window_private_free(WaylandWindowModePrivateData *pd) {\n  if (pd->toplevels) {\n    g_list_foreach(pd->toplevels, toplevels_list_item_free, NULL);\n    g_list_free(pd->toplevels);\n    pd->toplevels = NULL;\n  }\n\n  if (pd->registry) {\n    wl_registry_destroy(pd->registry);\n    pd->registry = NULL;\n  }\n\n  if (pd->manager) {\n    zwlr_foreign_toplevel_manager_v1_stop(pd->manager);\n    pd->manager = NULL;\n    wl_display_roundtrip(pd->wayland->display);\n  }\n\n  if (pd->window_regex) {\n    g_regex_unref(pd->window_regex);\n  }\n\n  g_free(pd);\n}\n\nstatic int wayland_window_mode_init(Mode *sw) {\n  /**\n   * Called on startup when enabled (in modi list)\n   */\n  if (mode_get_private_data(sw) == NULL) {\n    WaylandWindowModePrivateData *pd =\n        (WaylandWindowModePrivateData *)g_malloc0(\n            sizeof(WaylandWindowModePrivateData));\n    mode_set_private_data(sw, (void *)pd);\n\n    get_wayland_window(sw);\n  }\n  return TRUE;\n}\n\nstatic unsigned int wayland_window_mode_get_num_entries(const Mode *sw) {\n  const WaylandWindowModePrivateData *pd =\n      (const WaylandWindowModePrivateData *)mode_get_private_data(sw);\n\n  g_return_val_if_fail(pd != NULL, 0);\n\n  return g_list_length(pd->toplevels);\n}\n\nstatic ModeMode wayland_window_mode_result(Mode *sw, int mretv,\n                                           G_GNUC_UNUSED char **input,\n                                           unsigned int selected_line) {\n  ModeMode retv = MODE_EXIT;\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n\n  g_return_val_if_fail(pd != NULL, retv);\n\n  if (mretv & MENU_NEXT) {\n    retv = NEXT_DIALOG;\n  } else if (mretv & MENU_PREVIOUS) {\n    retv = PREVIOUS_DIALOG;\n  } else if (mretv & MENU_QUICK_SWITCH) {\n    retv = (ModeMode)(mretv & MENU_LOWER_MASK);\n  } else if ((mretv & MENU_OK)) {\n    rofi_view_hide();\n    ForeignToplevelHandle *toplevel =\n        (ForeignToplevelHandle *)g_list_nth_data(pd->toplevels, selected_line);\n    foreign_toplevel_handle_activate(toplevel, pd->wayland->last_seat->seat);\n    wl_display_flush(pd->wayland->display);\n\n  } else if ((mretv & MENU_ENTRY_DELETE) == MENU_ENTRY_DELETE) {\n    ForeignToplevelHandle *toplevel =\n        (ForeignToplevelHandle *)g_list_nth_data(pd->toplevels, selected_line);\n    foreign_toplevel_handle_close(toplevel);\n    wl_display_flush(pd->wayland->display);\n  }\n\n  return retv;\n}\n\nstatic void wayland_window_mode_destroy(Mode *sw) {\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n\n  if (pd == NULL) {\n    return;\n  }\n\n  wayland_window_private_free(pd);\n  mode_set_private_data(sw, NULL);\n}\n\nstatic int wayland_window_token_match(const Mode *sw, rofi_int_matcher **tokens,\n                                      unsigned int index) {\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n  ForeignToplevelHandle *toplevel =\n      (ForeignToplevelHandle *)g_list_nth_data(pd->toplevels, index);\n\n  g_return_val_if_fail(toplevel != NULL, 0);\n\n  int match = TRUE;\n\n  if (tokens) {\n    for (int j = 0; match && tokens[j] != NULL; j++) {\n      int test = 0;\n      /* See comment in window.c;\n       * for each token we want to match at least one field.\n       */\n      rofi_int_matcher *ftokens[2] = {tokens[j], NULL};\n\n      if ((pd->match_fields & WW_MATCH_FIELD_TITLE) &&\n          toplevel->title != NULL && toplevel->title[0] != '\\0') {\n        test = helper_token_match(ftokens, toplevel->title);\n      }\n\n      if (test == tokens[j]->invert &&\n          (pd->match_fields & WW_MATCH_FIELD_APP_ID) &&\n          toplevel->app_id != NULL && toplevel->app_id[0] != '\\0') {\n        test = helper_token_match(ftokens, toplevel->app_id);\n      }\n\n      if (test == 0) {\n        match = 0;\n      }\n    }\n  }\n\n  return match;\n}\n\nstatic void helper_eval_add_str(GString *str, const char *input, int len,\n                                int max_len, int nc) {\n  // g_utf8 does not work with NULL string.\n  const char *input_nn = input ? input : \"\";\n  // Both len and max_len are in characters, not bytes.\n  int spaces = 0;\n  if (len > 0) {\n    if (nc > len) {\n      int bl = g_utf8_offset_to_pointer(input_nn, len) - input_nn;\n      char *tmp = g_markup_escape_text(input_nn, bl);\n      g_string_append(str, tmp);\n      g_free(tmp);\n    } else {\n      spaces = len - nc;\n      char *tmp = g_markup_escape_text(input_nn, -1);\n      g_string_append(str, tmp);\n      g_free(tmp);\n    }\n  } else {\n    char *tmp = g_markup_escape_text(input_nn, -1);\n    g_string_append(str, tmp);\n    g_free(tmp);\n    if (len == 0) {\n      spaces = MAX(0, max_len - nc);\n    }\n  }\n  while (spaces--) {\n    g_string_append_c(str, ' ');\n  }\n}\n\nstruct arg {\n  const WaylandWindowModePrivateData *pd;\n  ForeignToplevelHandle *toplevel;\n};\n\nstatic gboolean helper_eval_cb(const GMatchInfo *info, GString *str,\n                               gpointer data) {\n  struct arg *d = (struct arg *)data;\n  gchar *match;\n  // Get the match\n  match = g_match_info_fetch(info, 0);\n  if (match != NULL) {\n    int l = 0;\n    if (match[2] == ':') {\n      l = (int)g_ascii_strtoll(&match[3], NULL, 10);\n    }\n    /* Most of the arguments are not supported on wayland */\n    switch (match[1]) {\n    case 't': /* title */\n      helper_eval_add_str(str, d->toplevel->title, l, d->pd->title_len,\n                          d->toplevel->title_len);\n      break;\n    case 'a': /* app_id */\n    case 'c': /* class */\n      helper_eval_add_str(str, d->toplevel->app_id, l, d->pd->app_id_len,\n                          d->toplevel->app_id_len);\n      break;\n    }\n\n    g_free(match);\n  }\n  return FALSE;\n}\n\nstatic char *_generate_display_string(const WaylandWindowModePrivateData *pd,\n                                      ForeignToplevelHandle *toplevel) {\n\n  struct arg d = {pd, toplevel};\n  char *res = g_regex_replace_eval(pd->window_regex, config.window_format, -1,\n                                   0, 0, helper_eval_cb, &d, NULL);\n  return g_strchomp(res);\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                int *state, G_GNUC_UNUSED GList **attr_list,\n                                int get_entry) {\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n\n  g_return_val_if_fail(pd != NULL, NULL);\n\n  ForeignToplevelHandle *toplevel =\n      (ForeignToplevelHandle *)g_list_nth_data(pd->toplevels, selected_line);\n\n  if (toplevel == NULL || toplevel->state & TOPLEVEL_STATE_CLOSED) {\n    return get_entry ? g_strdup(\"Window has vanished\") : NULL;\n  }\n\n  /* This may not work because layer-surface holds focus */\n  if (toplevel->state & TOPLEVEL_STATE_ACTIVATED) {\n    *state |= ACTIVE;\n  }\n  *state |= MARKUP;\n\n  return get_entry ? _generate_display_string(pd, toplevel) : NULL;\n}\n\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int height) {\n  WaylandWindowModePrivateData *pd =\n      (WaylandWindowModePrivateData *)mode_get_private_data(sw);\n  const guint scale = display_scale();\n\n  g_return_val_if_fail(pd != NULL, NULL);\n\n  ForeignToplevelHandle *toplevel =\n      (ForeignToplevelHandle *)g_list_nth_data(pd->toplevels, selected_line);\n\n  /* some apps don't have app_id (WM_CLASS). this is fine */\n  if (toplevel == NULL || toplevel->app_id == NULL ||\n      toplevel->app_id[0] == '\\0') {\n    return NULL;\n  }\n\n  if (toplevel->cached_icon_uid > 0 && toplevel->cached_icon_size == height &&\n      toplevel->cached_icon_scale == scale) {\n    return rofi_icon_fetcher_get(toplevel->cached_icon_uid);\n  }\n\n  /**\n   * Lookup icon by lowercase app_id.\n   * There's no API to request multiple names, so we do the same as XCB window\n   * mode and search for a lowercase WM_CLASS/app_id.\n   */\n  gchar *app_id_lower = g_utf8_strdown(toplevel->app_id, -1);\n  toplevel->cached_icon_size = height;\n  toplevel->cached_icon_scale = scale;\n  toplevel->cached_icon_uid = rofi_icon_fetcher_query(app_id_lower, height);\n  g_free(app_id_lower);\n\n  return rofi_icon_fetcher_get(toplevel->cached_icon_uid);\n}\n\n#include \"mode-private.h\"\n\nMode wayland_window_mode = {.name = \"window\",\n                            .cfg_name_key = \"display-window\",\n                            ._init = wayland_window_mode_init,\n                            ._destroy = wayland_window_mode_destroy,\n                            ._get_num_entries =\n                                wayland_window_mode_get_num_entries,\n                            ._result = wayland_window_mode_result,\n                            ._token_match = wayland_window_token_match,\n                            ._get_display_value = _get_display_value,\n                            ._get_icon = _get_icon,\n                            ._get_completion = NULL,\n                            ._preprocess_input = NULL,\n                            ._get_message = NULL,\n                            .private_data = NULL,\n                            .free = NULL,\n                            .type = MODE_TYPE_SWITCHER};\n\n#endif // WINDOW_MODE\n"
  },
  {
    "path": "source/modes/window.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this dialog. */\n#define G_LOG_DOMAIN \"Modes.Window\"\n\n#include \"config.h\"\n\n#ifdef WINDOW_MODE\n\n#include <errno.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <unistd.h>\n#include <xcb/xcb.h>\n#include <xcb/xcb_atom.h>\n#include <xcb/xcb_ewmh.h>\n#include <xcb/xcb_icccm.h>\n\n#include <glib.h>\n\n#include \"xcb-internal.h\"\n#include \"xcb.h\"\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"modes/window.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"widgets/textbox.h\"\n\n#include \"timings.h\"\n\n#include \"mode-private.h\"\n#include \"rofi-icon-fetcher.h\"\n\n#define WINLIST 32\n\n#define CLIENTSTATE 10\n#define CLIENTWINDOWTYPE 10\n\n// Fields to match in window mode\ntypedef struct {\n  char *field_name;\n  gboolean enabled;\n} WinModeField;\n\ntypedef enum {\n  WIN_MATCH_FIELD_TITLE,\n  WIN_MATCH_FIELD_CLASS,\n  WIN_MATCH_FIELD_ROLE,\n  WIN_MATCH_FIELD_NAME,\n  WIN_MATCH_FIELD_DESKTOP,\n  WIN_MATCH_NUM_FIELDS,\n} WinModeMatchingFields;\n\nstatic WinModeField matching_window_fields[WIN_MATCH_NUM_FIELDS] = {\n    {\n        .field_name = \"title\",\n        .enabled = TRUE,\n    },\n    {\n        .field_name = \"class\",\n        .enabled = TRUE,\n    },\n    {\n        .field_name = \"role\",\n        .enabled = TRUE,\n    },\n    {\n        .field_name = \"name\",\n        .enabled = TRUE,\n    },\n    {\n        .field_name = \"desktop\",\n        .enabled = TRUE,\n    }};\n\nstatic gboolean window_matching_fields_parsed = FALSE;\n\n// a manageable window\ntypedef struct {\n  xcb_window_t window;\n  xcb_get_window_attributes_reply_t xattr;\n  char *title;\n  char *class;\n  char *name;\n  char *role;\n  int states;\n  xcb_atom_t state[CLIENTSTATE];\n  int window_types;\n  xcb_atom_t window_type[CLIENTWINDOWTYPE];\n  int active;\n  int demands;\n  long hint_flags;\n  uint32_t wmdesktop;\n  char *wmdesktopstr;\n  unsigned int wmdesktopstr_len;\n  cairo_surface_t *icon;\n  gboolean icon_checked;\n  uint32_t icon_fetch_uid;\n  uint32_t icon_fetch_size;\n  guint icon_fetch_scale;\n  gboolean thumbnail_checked;\n  gboolean icon_theme_checked;\n} client;\n\n// window lists\ntypedef struct {\n  xcb_window_t *array;\n  client **data;\n  int len;\n} winlist;\n\ntypedef struct {\n  unsigned int id;\n  winlist *ids;\n  // Current window.\n  unsigned int index;\n  char *cache;\n  unsigned int wmdn_len;\n  unsigned int clf_len;\n  unsigned int name_len;\n  unsigned int title_len;\n  unsigned int role_len;\n  GRegex *window_regex;\n  // Hide current active window\n  gboolean hide_active_window;\n  gboolean prefer_icon_theme;\n} WindowModePrivateData;\n\nwinlist *cache_client = NULL;\n\n/**\n * Create a window list, pre-seeded with WINLIST entries.\n *\n * @returns A new window list.\n */\nstatic winlist *winlist_new(void) {\n  winlist *l = g_malloc(sizeof(winlist));\n  l->len = 0;\n  l->array = g_malloc_n(WINLIST + 1, sizeof(xcb_window_t));\n  l->data = g_malloc_n(WINLIST + 1, sizeof(client *));\n  return l;\n}\n\n/**\n * @param l The winlist.\n * @param w The window to add.\n * @param d Data pointer.\n *\n * Add one entry. If Full, extend with WINLIST entries.\n *\n * @returns -1 if failed, 0 or higher  is successful.\n */\nstatic int winlist_append(winlist *l, xcb_window_t w, client *d) {\n  if (l->len > 0 && !(l->len % WINLIST)) {\n    l->array =\n        g_realloc(l->array, sizeof(xcb_window_t) * (l->len + WINLIST + 1));\n    l->data = g_realloc(l->data, sizeof(client *) * (l->len + WINLIST + 1));\n  }\n  // Make clang-check happy.\n  // TODO: make clang-check clear this should never be 0.\n  if (l->data == NULL || l->array == NULL) {\n    return -1;\n  }\n\n  l->data[l->len] = d;\n  l->array[l->len++] = w;\n  return l->len - 1;\n}\n\nstatic void client_free(client *c) {\n  if (c == NULL) {\n    return;\n  }\n  if (c->icon) {\n    cairo_surface_destroy(c->icon);\n  }\n  g_free(c->title);\n  g_free(c->class);\n  g_free(c->name);\n  g_free(c->role);\n  g_free(c->wmdesktopstr);\n}\nstatic void winlist_empty(winlist *l) {\n  while (l->len > 0) {\n    client *c = l->data[--l->len];\n    if (c != NULL) {\n      client_free(c);\n      g_free(c);\n    }\n  }\n}\n\n/**\n * @param l The winlist entry\n *\n * Free the winlist.\n */\nstatic void winlist_free(winlist *l) {\n  if (l != NULL) {\n    winlist_empty(l);\n    g_free(l->array);\n    g_free(l->data);\n    g_free(l);\n  }\n}\n\n/**\n * @param l The winlist.\n * @param w The window to find.\n *\n * Find the window in the list, and return the array entry.\n *\n * @returns -1 if failed, index is successful.\n */\nstatic int winlist_find(winlist *l, xcb_window_t w) {\n  if (l == NULL) {\n    return -1;\n  }\n  // iterate backwards. Theory is: windows most often accessed will be\n  // nearer the end. Testing with kcachegrind seems to support this...\n  int i;\n\n  for (i = (l->len - 1); i >= 0; i--) {\n    if (l->array[i] == w) {\n      return i;\n    }\n  }\n\n  return -1;\n}\n/**\n * Create empty X11 cache for windows and windows attributes.\n */\nstatic void x11_cache_create(void) {\n  if (cache_client == NULL) {\n    cache_client = winlist_new();\n  }\n}\n\n/**\n * Free the cache.\n */\nstatic void x11_cache_free(void) {\n  winlist_free(cache_client);\n  cache_client = NULL;\n}\n\n/**\n * @param d Display connection to X server\n * @param w window\n *\n * Get window attributes.\n * This functions uses caching.\n *\n * @returns a XWindowAttributes\n */\nstatic xcb_get_window_attributes_reply_t *\nwindow_get_attributes(xcb_window_t w) {\n  xcb_get_window_attributes_cookie_t c =\n      xcb_get_window_attributes(xcb->connection, w);\n  xcb_get_window_attributes_reply_t *r =\n      xcb_get_window_attributes_reply(xcb->connection, c, NULL);\n  if (r) {\n    return r;\n  }\n  return NULL;\n}\n// _NET_WM_STATE_*\nstatic int client_has_state(client *c, xcb_atom_t state) {\n  for (int i = 0; i < c->states; i++) {\n    if (c->state[i] == state) {\n      return 1;\n    }\n  }\n\n  return 0;\n}\nstatic int client_has_window_type(client *c, xcb_atom_t type) {\n  for (int i = 0; i < c->window_types; i++) {\n    if (c->window_type[i] == type) {\n      return 1;\n    }\n  }\n\n  return 0;\n}\n\nstatic client *window_client(WindowModePrivateData *pd, xcb_window_t win) {\n  if (win == XCB_WINDOW_NONE) {\n    return NULL;\n  }\n\n  int idx = winlist_find(cache_client, win);\n\n  if (idx >= 0) {\n    return cache_client->data[idx];\n  }\n\n  // if this fails, we're up that creek\n  xcb_get_window_attributes_reply_t *attr = window_get_attributes(win);\n\n  if (!attr) {\n    return NULL;\n  }\n  client *c = g_malloc0(sizeof(client));\n  c->window = win;\n\n  // copy xattr so we don't have to care when stuff is freed\n  memmove(&c->xattr, attr, sizeof(xcb_get_window_attributes_reply_t));\n\n  xcb_get_property_cookie_t cky = xcb_ewmh_get_wm_state(&xcb->ewmh, win);\n  xcb_ewmh_get_atoms_reply_t states;\n  if (xcb_ewmh_get_wm_state_reply(&xcb->ewmh, cky, &states, NULL)) {\n    c->states = MIN(CLIENTSTATE, states.atoms_len);\n    memcpy(c->state, states.atoms,\n           MIN(CLIENTSTATE, states.atoms_len) * sizeof(xcb_atom_t));\n    xcb_ewmh_get_atoms_reply_wipe(&states);\n  }\n  cky = xcb_ewmh_get_wm_window_type(&xcb->ewmh, win);\n  if (xcb_ewmh_get_wm_window_type_reply(&xcb->ewmh, cky, &states, NULL)) {\n    c->window_types = MIN(CLIENTWINDOWTYPE, states.atoms_len);\n    memcpy(c->window_type, states.atoms,\n           MIN(CLIENTWINDOWTYPE, states.atoms_len) * sizeof(xcb_atom_t));\n    xcb_ewmh_get_atoms_reply_wipe(&states);\n  }\n\n  char *tmp_title = window_get_text_prop(c->window, xcb->ewmh._NET_WM_NAME);\n  if (tmp_title == NULL) {\n    tmp_title = window_get_text_prop(c->window, XCB_ATOM_WM_NAME);\n  }\n  if (tmp_title != NULL) {\n    c->title = g_markup_escape_text(tmp_title, -1);\n  } else {\n    c->title = g_strdup(\"<i>no title set</i>\");\n  }\n  pd->title_len =\n      MAX(c->title ? g_utf8_strlen(c->title, -1) : 0, pd->title_len);\n  g_free(tmp_title);\n\n  char *tmp_role = window_get_text_prop(c->window, netatoms[WM_WINDOW_ROLE]);\n  c->role = g_markup_escape_text(tmp_role ? tmp_role : \"\", -1);\n  pd->role_len = MAX(c->role ? g_utf8_strlen(c->role, -1) : 0, pd->role_len);\n  g_free(tmp_role);\n\n  cky = xcb_icccm_get_wm_class(xcb->connection, c->window);\n  xcb_icccm_get_wm_class_reply_t wcr;\n  if (xcb_icccm_get_wm_class_reply(xcb->connection, cky, &wcr, NULL)) {\n    c->class = g_markup_escape_text(wcr.class_name, -1);\n    c->name = g_markup_escape_text(wcr.instance_name, -1);\n    pd->name_len = MAX(c->name ? g_utf8_strlen(c->name, -1) : 0, pd->name_len);\n    xcb_icccm_get_wm_class_reply_wipe(&wcr);\n  }\n\n  xcb_get_property_cookie_t cc =\n      xcb_icccm_get_wm_hints(xcb->connection, c->window);\n  xcb_icccm_wm_hints_t r;\n  if (xcb_icccm_get_wm_hints_reply(xcb->connection, cc, &r, NULL)) {\n    c->hint_flags = r.flags;\n  }\n\n  idx = winlist_append(cache_client, c->window, c);\n  // Should never happen.\n  if (idx < 0) {\n    client_free(c);\n    g_free(c);\n    c = NULL;\n  }\n  g_free(attr);\n  return c;\n}\n\nguint window_reload_timeout = 0;\nstatic gboolean window_client_reload(G_GNUC_UNUSED void *data) {\n  window_reload_timeout = 0;\n  if (window_mode.private_data) {\n    window_mode._destroy(&window_mode);\n    window_mode._init(&window_mode);\n  }\n  if (window_mode_cd.private_data) {\n    window_mode_cd._destroy(&window_mode_cd);\n    window_mode_cd._init(&window_mode_cd);\n  }\n  if (window_mode.private_data || window_mode_cd.private_data) {\n    rofi_view_reload();\n  }\n  return G_SOURCE_REMOVE;\n}\nvoid window_client_handle_signal(G_GNUC_UNUSED xcb_window_t win,\n                                 G_GNUC_UNUSED gboolean create) {\n  //  g_idle_add_full(G_PRIORITY_HIGH_IDLE, window_client_reload, NULL, NULL);\n  if (window_reload_timeout > 0) {\n    g_source_remove(window_reload_timeout);\n    window_reload_timeout = 0;\n  }\n  window_reload_timeout = g_timeout_add(100, window_client_reload, NULL);\n}\nstatic int window_match(const Mode *sw, rofi_int_matcher **tokens,\n                        unsigned int index) {\n  WindowModePrivateData *rmpd =\n      (WindowModePrivateData *)mode_get_private_data(sw);\n  int match = 1;\n  const winlist *ids = (winlist *)rmpd->ids;\n  // Want to pull directly out of cache, X calls are not thread safe.\n  int idx = winlist_find(cache_client, ids->array[index]);\n  g_assert(idx >= 0);\n  client *c = cache_client->data[idx];\n\n  if (tokens) {\n    for (int j = 0; match && tokens[j] != NULL; j++) {\n      int test = 0;\n      // Dirty hack. Normally helper_token_match does _all_ the matching,\n      // Now we want it to match only one item at the time.\n      // If hack not in place it would not match queries spanning multiple\n      // fields. e.g. when searching 'title element' and 'class element'\n      rofi_int_matcher *ftokens[2] = {tokens[j], NULL};\n      if (c->title != NULL && c->title[0] != '\\0' &&\n          matching_window_fields[WIN_MATCH_FIELD_TITLE].enabled) {\n        test = helper_token_match(ftokens, c->title);\n      }\n\n      if (test == tokens[j]->invert && c->class != NULL &&\n          c->class[0] != '\\0' &&\n          matching_window_fields[WIN_MATCH_FIELD_CLASS].enabled) {\n        test = helper_token_match(ftokens, c->class);\n      }\n\n      if (test == tokens[j]->invert && c->role != NULL && c->role[0] != '\\0' &&\n          matching_window_fields[WIN_MATCH_FIELD_ROLE].enabled) {\n        test = helper_token_match(ftokens, c->role);\n      }\n\n      if (test == tokens[j]->invert && c->name != NULL && c->name[0] != '\\0' &&\n          matching_window_fields[WIN_MATCH_FIELD_NAME].enabled) {\n        test = helper_token_match(ftokens, c->name);\n      }\n      if (test == tokens[j]->invert && c->wmdesktopstr != NULL &&\n          c->wmdesktopstr[0] != '\\0' &&\n          matching_window_fields[WIN_MATCH_FIELD_DESKTOP].enabled) {\n        test = helper_token_match(ftokens, c->wmdesktopstr);\n      }\n\n      if (test == 0) {\n        match = 0;\n      }\n    }\n  }\n\n  return match;\n}\n\nstatic void window_mode_parse_fields(void) {\n  window_matching_fields_parsed = TRUE;\n  char *savept = NULL;\n  // Make a copy, as strtok will modify it.\n  char *switcher_str = g_strdup(config.window_match_fields);\n  const char *const sep = \",#\";\n  // Split token on ','. This modifies switcher_str.\n  for (unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++) {\n    matching_window_fields[i].enabled = FALSE;\n  }\n  for (char *token = strtok_r(switcher_str, sep, &savept); token != NULL;\n       token = strtok_r(NULL, sep, &savept)) {\n    if (strcmp(token, \"all\") == 0) {\n      for (unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++) {\n        matching_window_fields[i].enabled = TRUE;\n      }\n      break;\n    }\n    gboolean matched = FALSE;\n    for (unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++) {\n      const char *field_name = matching_window_fields[i].field_name;\n      if (strcmp(token, field_name) == 0) {\n        matching_window_fields[i].enabled = TRUE;\n        matched = TRUE;\n      }\n    }\n    if (!matched) {\n      g_warning(\"Invalid window field name :%s\", token);\n    }\n  }\n  // Free string that was modified by strtok_r\n  g_free(switcher_str);\n}\n\nstatic unsigned int window_mode_get_num_entries(const Mode *sw) {\n  const WindowModePrivateData *pd =\n      (const WindowModePrivateData *)mode_get_private_data(sw);\n\n  return pd->ids ? pd->ids->len : 0;\n}\n/**\n * Small helper function to find the right entry in the ewmh reply.\n * Is there a call for this?\n */\nconst char *invalid_desktop_name = \"n/a\";\nstatic const char *_window_name_list_entry(const char *str, uint32_t length,\n                                           int entry) {\n  uint32_t offset = 0;\n  int index = 0;\n  while (index < entry && offset < length) {\n    if (str[offset] == 0) {\n      index++;\n    }\n    offset++;\n  }\n  if (offset >= length) {\n    return invalid_desktop_name;\n  }\n  return &str[offset];\n}\nstatic void _window_mode_load_data(Mode *sw, unsigned int cd) {\n  WindowModePrivateData *pd =\n      (WindowModePrivateData *)mode_get_private_data(sw);\n  // find window list\n  xcb_window_t curr_win_id;\n  int found = 0;\n\n  // Create cache\n\n  x11_cache_create();\n  xcb_get_property_cookie_t c =\n      xcb_ewmh_get_active_window(&(xcb->ewmh), xcb->screen_nbr);\n  if (!xcb_ewmh_get_active_window_reply(&xcb->ewmh, c, &curr_win_id, NULL)) {\n    curr_win_id = 0;\n  }\n\n  // Get the current desktop.\n  unsigned int current_desktop = 0;\n  c = xcb_ewmh_get_current_desktop(&xcb->ewmh, xcb->screen_nbr);\n  if (!xcb_ewmh_get_current_desktop_reply(&xcb->ewmh, c, &current_desktop,\n                                          NULL)) {\n    current_desktop = 0;\n  }\n\n  g_debug(\"Get list from: %d\", xcb->screen_nbr);\n  c = xcb_ewmh_get_client_list_stacking(&xcb->ewmh, xcb->screen_nbr);\n  xcb_ewmh_get_windows_reply_t clients = {\n      0,\n  };\n  if (xcb_ewmh_get_client_list_stacking_reply(&xcb->ewmh, c, &clients, NULL)) {\n    found = 1;\n  } else {\n    c = xcb_ewmh_get_client_list(&xcb->ewmh, xcb->screen_nbr);\n    if (xcb_ewmh_get_client_list_reply(&xcb->ewmh, c, &clients, NULL)) {\n      found = 1;\n    }\n  }\n  if (!found) {\n    return;\n  }\n\n  if (clients.windows_len > 0) {\n    int i;\n    // windows we actually display. May be slightly different to\n    // _NET_CLIENT_LIST_STACKING if we happen to have a window destroyed while\n    // we're working...\n    pd->ids = winlist_new();\n\n    int has_names = FALSE;\n    ssize_t ws_names_length = 0;\n    char *ws_names = NULL;\n    xcb_get_property_cookie_t prop_cookie =\n        xcb_ewmh_get_desktop_names(&xcb->ewmh, xcb->screen_nbr);\n    xcb_ewmh_get_utf8_strings_reply_t names;\n    if (xcb_ewmh_get_desktop_names_reply(&xcb->ewmh, prop_cookie, &names,\n                                         NULL)) {\n      ws_names_length = names.strings_len;\n      ws_names = g_malloc0_n(names.strings_len + 1, sizeof(char));\n      memcpy(ws_names, names.strings, names.strings_len);\n      has_names = TRUE;\n      xcb_ewmh_get_utf8_strings_reply_wipe(&names);\n    }\n    // calc widths of fields\n    for (i = clients.windows_len - 1; i > -1; i--) {\n      client *winclient = window_client(pd, clients.windows[i]);\n      if ((winclient != NULL) && !winclient->xattr.override_redirect &&\n          !client_has_window_type(winclient,\n                                  xcb->ewmh._NET_WM_WINDOW_TYPE_DOCK) &&\n          !client_has_window_type(winclient,\n                                  xcb->ewmh._NET_WM_WINDOW_TYPE_DESKTOP) &&\n          !client_has_state(winclient, xcb->ewmh._NET_WM_STATE_SKIP_PAGER) &&\n          !client_has_state(winclient, xcb->ewmh._NET_WM_STATE_SKIP_TASKBAR)) {\n        pd->clf_len =\n            MAX(pd->clf_len, (winclient->class != NULL)\n                                 ? (g_utf8_strlen(winclient->class, -1))\n                                 : 0);\n\n        if (client_has_state(winclient,\n                             xcb->ewmh._NET_WM_STATE_DEMANDS_ATTENTION)) {\n          winclient->demands = TRUE;\n        }\n        if ((winclient->hint_flags & XCB_ICCCM_WM_HINT_X_URGENCY) != 0) {\n          winclient->demands = TRUE;\n        }\n\n        if (winclient->window == curr_win_id) {\n          winclient->active = TRUE;\n        }\n        // find client's desktop.\n        xcb_get_property_cookie_t cookie;\n        xcb_get_property_reply_t *r;\n\n        winclient->wmdesktop = 0xFFFFFFFF;\n        cookie = xcb_get_property(xcb->connection, 0, winclient->window,\n                                  xcb->ewmh._NET_WM_DESKTOP, XCB_ATOM_CARDINAL,\n                                  0, 1);\n        r = xcb_get_property_reply(xcb->connection, cookie, NULL);\n        if (r) {\n          if (r->type == XCB_ATOM_CARDINAL) {\n            winclient->wmdesktop = *((uint32_t *)xcb_get_property_value(r));\n          }\n          free(r);\n        }\n        if (winclient->wmdesktop != 0xFFFFFFFF) {\n          if (has_names) {\n            if ((current_window_manager & WM_PANGO_WORKSPACE_NAMES) ==\n                WM_PANGO_WORKSPACE_NAMES) {\n              char *output = NULL;\n              if (pango_parse_markup(\n                      _window_name_list_entry(ws_names, ws_names_length,\n                                              winclient->wmdesktop),\n                      -1, 0, NULL, &output, NULL, NULL)) {\n                winclient->wmdesktopstr = g_strdup(_window_name_list_entry(\n                    ws_names, ws_names_length, winclient->wmdesktop));\n                winclient->wmdesktopstr_len = g_utf8_strlen(output, -1);\n                pd->wmdn_len = MAX(pd->wmdn_len, winclient->wmdesktopstr_len);\n                g_free(output);\n              } else {\n                winclient->wmdesktopstr = g_strdup(\"Invalid name\");\n                winclient->wmdesktopstr_len =\n                    g_utf8_strlen(winclient->wmdesktopstr, -1);\n                pd->wmdn_len = MAX(pd->wmdn_len, winclient->wmdesktopstr_len);\n              }\n            } else {\n              winclient->wmdesktopstr = g_markup_escape_text(\n                  _window_name_list_entry(ws_names, ws_names_length,\n                                          winclient->wmdesktop),\n                  -1);\n              winclient->wmdesktopstr_len =\n                  g_utf8_strlen(winclient->wmdesktopstr, -1);\n              pd->wmdn_len = MAX(pd->wmdn_len, winclient->wmdesktopstr_len);\n            }\n          } else {\n            winclient->wmdesktopstr =\n                g_strdup_printf(\"%u\", (uint32_t)winclient->wmdesktop);\n            winclient->wmdesktopstr_len =\n                g_utf8_strlen(winclient->wmdesktopstr, -1);\n            pd->wmdn_len = MAX(pd->wmdn_len, winclient->wmdesktopstr_len);\n          }\n        } else {\n          winclient->wmdesktopstr = g_strdup(\"\");\n          winclient->wmdesktopstr_len =\n              g_utf8_strlen(winclient->wmdesktopstr, -1);\n          pd->wmdn_len = MAX(pd->wmdn_len, winclient->wmdesktopstr_len);\n        }\n        if (cd && winclient->wmdesktop != current_desktop) {\n          continue;\n        }\n        if (!pd->hide_active_window || winclient->window != curr_win_id) {\n          winlist_append(pd->ids, winclient->window, NULL);\n        }\n      }\n    }\n\n    if (has_names) {\n      g_free(ws_names);\n    }\n  }\n  xcb_ewmh_get_windows_reply_wipe(&clients);\n}\nstatic int window_mode_init(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n\n    WindowModePrivateData *pd = g_malloc0(sizeof(*pd));\n    ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"hide-active-window\", FALSE);\n    if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n      pd->hide_active_window = TRUE;\n    }\n    // prefer icon theme selection\n    p = rofi_theme_find_property(wid, P_BOOLEAN, \"prefer-icon-theme\", FALSE);\n    if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n      pd->prefer_icon_theme = TRUE;\n    }\n    pd->window_regex = g_regex_new(\"{[-\\\\w]+(:-?[0-9]+)?}\", 0, 0, NULL);\n    mode_set_private_data(sw, (void *)pd);\n    _window_mode_load_data(sw, FALSE);\n    if (!window_matching_fields_parsed) {\n      window_mode_parse_fields();\n    }\n  }\n  return TRUE;\n}\nstatic int window_mode_init_cd(Mode *sw) {\n  if (mode_get_private_data(sw) == NULL) {\n    WindowModePrivateData *pd = g_malloc0(sizeof(*pd));\n\n    ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"hide-active-window\", FALSE);\n    if (p && p->type == P_BOOLEAN && p->value.b == TRUE) {\n      pd->hide_active_window = TRUE;\n    }\n    pd->window_regex = g_regex_new(\"{[-\\\\w]+(:-?[0-9]+)?}\", 0, 0, NULL);\n    mode_set_private_data(sw, (void *)pd);\n    _window_mode_load_data(sw, TRUE);\n    if (!window_matching_fields_parsed) {\n      window_mode_parse_fields();\n    }\n  }\n  return TRUE;\n}\n\nstatic inline int act_on_window(xcb_window_t window) {\n  int retv = TRUE;\n  char **args = NULL;\n  int argc = 0;\n  char window_regex[100]; /* We are probably safe here */\n\n  g_snprintf(window_regex, sizeof window_regex, \"%d\", window);\n\n  helper_parse_setup(config.window_command, &args, &argc, \"{window}\",\n                     window_regex, (char *)0);\n\n  GError *error = NULL;\n  g_spawn_async(NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL,\n                &error);\n  if (error != NULL) {\n    char *msg = g_strdup_printf(\n        \"Failed to execute action for window: '%s'\\nError: '%s'\", window_regex,\n        error->message);\n    rofi_view_error_dialog(msg, FALSE);\n    g_free(msg);\n    // print error.\n    g_error_free(error);\n    retv = FALSE;\n  }\n\n  // Free the args list.\n  g_strfreev(args);\n  return retv;\n}\n\nstatic ModeMode window_mode_result(Mode *sw, int mretv,\n                                   G_GNUC_UNUSED char **input,\n                                   unsigned int selected_line) {\n  WindowModePrivateData *rmpd =\n      (WindowModePrivateData *)mode_get_private_data(sw);\n  ModeMode retv = MODE_EXIT;\n  if ((mretv & (MENU_OK))) {\n    if (mretv & MENU_CUSTOM_ACTION) {\n      act_on_window(rmpd->ids->array[selected_line]);\n    } else {\n      // Disable reverting input focus to previous window.\n      xcb->focus_revert = 0;\n      rofi_view_hide();\n      if ((current_window_manager & WM_DO_NOT_CHANGE_CURRENT_DESKTOP) == 0) {\n        // Get the desktop of the client to switch to\n        uint32_t wmdesktop = 0;\n        xcb_get_property_cookie_t cookie;\n        xcb_get_property_reply_t *r;\n        // Get the current desktop.\n        unsigned int current_desktop = 0;\n        xcb_get_property_cookie_t c =\n            xcb_ewmh_get_current_desktop(&xcb->ewmh, xcb->screen_nbr);\n        if (!xcb_ewmh_get_current_desktop_reply(&xcb->ewmh, c, &current_desktop,\n                                                NULL)) {\n          current_desktop = 0;\n        }\n\n        cookie = xcb_get_property(\n            xcb->connection, 0, rmpd->ids->array[selected_line],\n            xcb->ewmh._NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 0, 1);\n        r = xcb_get_property_reply(xcb->connection, cookie, NULL);\n        if (r && r->type == XCB_ATOM_CARDINAL) {\n          wmdesktop = *((uint32_t *)xcb_get_property_value(r));\n        }\n        if (r && r->type != XCB_ATOM_CARDINAL) {\n          // Assume the client is on all desktops.\n          wmdesktop = current_desktop;\n        }\n        free(r);\n\n        // If we have to switch the desktop, do\n        if (wmdesktop != current_desktop) {\n          xcb_ewmh_request_change_current_desktop(&xcb->ewmh, xcb->screen_nbr,\n                                                  wmdesktop, XCB_CURRENT_TIME);\n        }\n      }\n      // Activate the window\n      xcb_ewmh_request_change_active_window(\n          &xcb->ewmh, xcb->screen_nbr, rmpd->ids->array[selected_line],\n          XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER, XCB_CURRENT_TIME,\n          rofi_view_get_window());\n      xcb_flush(xcb->connection);\n    }\n  } else if ((mretv & (MENU_ENTRY_DELETE)) == MENU_ENTRY_DELETE) {\n    xcb_ewmh_request_close_window(\n        &(xcb->ewmh), xcb->screen_nbr, rmpd->ids->array[selected_line],\n        XCB_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER);\n    xcb_flush(xcb->connection);\n    ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);\n    Property *p =\n        rofi_theme_find_property(wid, P_BOOLEAN, \"close-on-delete\", TRUE);\n    if (p && p->type == P_BOOLEAN && p->value.b == FALSE) {\n\n      return RELOAD_DIALOG;\n    }\n  } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&\n             *input[0] != '\\0') {\n    GError *error = NULL;\n    gboolean run_in_term = ((mretv & MENU_CUSTOM_ACTION) == MENU_CUSTOM_ACTION);\n    gsize lf_cmd_size = 0;\n    gchar *lf_cmd = g_locale_from_utf8(*input, -1, NULL, &lf_cmd_size, &error);\n    if (error != NULL) {\n      g_warning(\"Failed to convert command to locale encoding: %s\",\n                error->message);\n      g_error_free(error);\n      return RELOAD_DIALOG;\n    }\n\n    RofiHelperExecuteContext context = {.name = NULL};\n    if (!helper_execute_command(NULL, lf_cmd, run_in_term,\n                                run_in_term ? &context : NULL)) {\n      retv = RELOAD_DIALOG;\n    }\n    g_free(lf_cmd);\n  } else if (mretv & MENU_CUSTOM_COMMAND) {\n    retv = (mretv & MENU_LOWER_MASK);\n  }\n  return retv;\n}\n\nstatic void window_mode_destroy(Mode *sw) {\n  WindowModePrivateData *rmpd =\n      (WindowModePrivateData *)mode_get_private_data(sw);\n  if (rmpd != NULL) {\n    winlist_free(rmpd->ids);\n    x11_cache_free();\n    g_free(rmpd->cache);\n    g_regex_unref(rmpd->window_regex);\n    g_free(rmpd);\n    mode_set_private_data(sw, NULL);\n  }\n}\nstruct arg {\n  const WindowModePrivateData *pd;\n  const client *c;\n};\n\nstatic void helper_eval_add_str(GString *str, const char *input, int l,\n                                int max_len, int nc) {\n  // g_utf8 does not work with NULL string.\n  const char *input_nn = input ? input : \"\";\n  // Both l and max_len are in characters, not bytes.\n  int spaces = 0;\n  if (l > 0) {\n    if (nc > l) {\n      int bl = g_utf8_offset_to_pointer(input_nn, l) - input_nn;\n      char *tmp = g_markup_escape_text(input_nn, bl);\n      g_string_append(str, tmp);\n      g_free(tmp);\n    } else {\n      spaces = l - nc;\n      char *tmp = g_markup_escape_text(input_nn, -1);\n      g_string_append(str, tmp);\n      g_free(tmp);\n    }\n  } else {\n    g_string_append(str, input_nn);\n    if (l == 0) {\n      spaces = MAX(0, max_len - nc);\n    }\n  }\n  while (spaces--) {\n    g_string_append_c(str, ' ');\n  }\n}\nstatic gboolean helper_eval_cb(const GMatchInfo *info, GString *str,\n                               gpointer data) {\n  struct arg *d = (struct arg *)data;\n  gchar *match;\n  // Get the match\n  match = g_match_info_fetch(info, 0);\n  if (match != NULL) {\n    int l = 0;\n    if (match[2] == ':') {\n      l = (int)g_ascii_strtoll(&match[3], NULL, 10);\n    }\n    if (match[1] == 'w') {\n      helper_eval_add_str(str, d->c->wmdesktopstr, l, d->pd->wmdn_len,\n                          d->c->wmdesktopstr_len);\n    } else if (match[1] == 'c') {\n      helper_eval_add_str(str, d->c->class, l, d->pd->clf_len,\n                          g_utf8_strlen(d->c->class, -1));\n    } else if (match[1] == 't') {\n      helper_eval_add_str(str, d->c->title, l, d->pd->title_len,\n                          g_utf8_strlen(d->c->title, -1));\n    } else if (match[1] == 'n') {\n      helper_eval_add_str(str, d->c->name, l, d->pd->name_len,\n                          g_utf8_strlen(d->c->name, -1));\n    } else if (match[1] == 'r') {\n      helper_eval_add_str(str, d->c->role, l, d->pd->role_len,\n                          g_utf8_strlen(d->c->role, -1));\n    }\n\n    g_free(match);\n  }\n  return FALSE;\n}\nstatic char *_generate_display_string(const WindowModePrivateData *pd,\n                                      const client *c) {\n  struct arg d = {pd, c};\n  char *res = g_regex_replace_eval(pd->window_regex, config.window_format, -1,\n                                   0, 0, helper_eval_cb, &d, NULL);\n  return g_strchomp(res);\n}\n\nstatic char *_get_display_value(const Mode *sw, unsigned int selected_line,\n                                int *state, G_GNUC_UNUSED GList **list,\n                                int get_entry) {\n  WindowModePrivateData *rmpd = mode_get_private_data(sw);\n  const client *c = window_client(rmpd, rmpd->ids->array[selected_line]);\n  if (c == NULL) {\n    return get_entry ? g_strdup(\"Window has vanished\") : NULL;\n  }\n  if (c->demands) {\n    *state |= URGENT;\n  }\n  if (c->active) {\n    *state |= ACTIVE;\n  }\n  *state |= MARKUP;\n  return get_entry ? _generate_display_string(rmpd, c) : NULL;\n}\n\n/**\n * Icon code borrowed from https://github.com/olejorgenb/extract-window-icon\n */\nstatic cairo_user_data_key_t data_key;\n\n/** Create a surface object from this image data.\n * \\param width The width of the image.\n * \\param height The height of the image\n * \\param data The image's data in ARGB format, will be copied by this\n * function.\n */\nstatic cairo_surface_t *draw_surface_from_data(uint32_t width, uint32_t height,\n                                               uint32_t const *const data) {\n  // limit surface size.\n  if (width >= 65536 || height >= 65536) {\n    return NULL;\n  }\n  uint32_t len = width * height;\n  uint32_t i;\n  uint32_t *buffer = g_new0(uint32_t, len);\n  cairo_surface_t *surface;\n\n  /* Cairo wants premultiplied alpha, meh :( */\n  for (i = 0; i < len; i++) {\n    uint8_t a = (data[i] >> 24) & 0xff;\n    double alpha = a / 255.0;\n    uint8_t r = ((data[i] >> 16) & 0xff) * alpha;\n    uint8_t g = ((data[i] >> 8) & 0xff) * alpha;\n    uint8_t b = ((data[i] >> 0) & 0xff) * alpha;\n    buffer[i] = (a << 24) | (r << 16) | (g << 8) | b;\n  }\n\n  surface = cairo_image_surface_create_for_data(\n      (unsigned char *)buffer, CAIRO_FORMAT_ARGB32, width, height, width * 4);\n  /* This makes sure that buffer will be freed */\n  cairo_surface_set_user_data(surface, &data_key, buffer, g_free);\n\n  return surface;\n}\nstatic cairo_surface_t *ewmh_window_icon_from_reply(xcb_get_property_reply_t *r,\n                                                    uint32_t preferred_size) {\n  uint32_t *data, *end, *found_data = 0;\n  uint32_t found_size = 0;\n\n  if (!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2) {\n    return 0;\n  }\n\n  data = (uint32_t *)xcb_get_property_value(r);\n  if (!data) {\n    return 0;\n  }\n\n  end = data + r->length;\n\n  /* Goes over the icon data and picks the icon that best matches the size\n   * preference. In case the size match is not exact, picks the closest bigger\n   * size if present, closest smaller size otherwise.\n   */\n  while (data + 1 < end) {\n    /* check whether the data size specified by width and height fits into the\n     * array we got */\n    uint64_t data_size = (uint64_t)data[0] * data[1];\n    if (data_size > (uint64_t)(end - data - 2)) {\n      break;\n    }\n\n    /* use the greater of the two dimensions to match against the preferred\n     * size\n     */\n    uint32_t size = MAX(data[0], data[1]);\n\n    /* pick the icon if it's a better match than the one we already have */\n    gboolean found_icon_too_small = found_size < preferred_size;\n    gboolean found_icon_too_large = found_size > preferred_size;\n    gboolean icon_empty = data[0] == 0 || data[1] == 0;\n    gboolean better_because_bigger = found_icon_too_small && size > found_size;\n    gboolean better_because_smaller =\n        found_icon_too_large && size >= preferred_size && size < found_size;\n    if (!icon_empty &&\n        (better_because_bigger || better_because_smaller || found_size == 0)) {\n      found_data = data;\n      found_size = size;\n    }\n\n    data += data_size + 2;\n  }\n\n  if (!found_data) {\n    return 0;\n  }\n\n  return draw_surface_from_data(found_data[0], found_data[1], found_data + 2);\n}\n/** Get NET_WM_ICON. */\nstatic cairo_surface_t *get_net_wm_icon(xcb_window_t xid,\n                                        uint32_t preferred_size) {\n  xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(\n      xcb->connection, FALSE, xid, xcb->ewmh._NET_WM_ICON, XCB_ATOM_CARDINAL, 0,\n      UINT32_MAX);\n  xcb_get_property_reply_t *r =\n      xcb_get_property_reply(xcb->connection, cookie, NULL);\n  cairo_surface_t *surface = ewmh_window_icon_from_reply(r, preferred_size);\n  free(r);\n  return surface;\n}\nstatic cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,\n                                  unsigned int size) {\n  WindowModePrivateData *rmpd = mode_get_private_data(sw);\n  const guint scale = display_scale();\n  client *c = window_client(rmpd, rmpd->ids->array[selected_line]);\n  if (c == NULL) {\n    return NULL;\n  }\n  if (c->icon_fetch_size != size || c->icon_fetch_scale != scale) {\n    if (c->icon) {\n      cairo_surface_destroy(c->icon);\n      c->icon = NULL;\n    }\n    c->thumbnail_checked = FALSE;\n    c->icon_checked = FALSE;\n    c->icon_theme_checked = FALSE;\n  }\n  // TODO: apply scaling to the following two routines\n  if (config.window_thumbnail && c->thumbnail_checked == FALSE) {\n    c->icon = x11_helper_get_screenshot_surface_window(c->window, size);\n    c->thumbnail_checked = TRUE;\n  }\n  if (rmpd->prefer_icon_theme == FALSE) {\n    if (c->icon == NULL && c->icon_checked == FALSE) {\n      c->icon = get_net_wm_icon(rmpd->ids->array[selected_line], size);\n      c->icon_checked = TRUE;\n    }\n    if (c->icon == NULL && c->class && c->icon_theme_checked == FALSE) {\n      if (c->icon_fetch_uid == 0) {\n        char *class_lower = g_utf8_strdown(c->class, -1);\n        c->icon_fetch_uid = rofi_icon_fetcher_query(class_lower, size);\n        g_free(class_lower);\n        c->icon_fetch_size = size;\n        c->icon_fetch_scale = scale;\n      }\n      c->icon_theme_checked =\n          rofi_icon_fetcher_get_ex(c->icon_fetch_uid, &(c->icon));\n      if (c->icon) {\n        cairo_surface_reference(c->icon);\n      }\n    }\n  } else {\n    if (c->icon == NULL && c->class && c->icon_theme_checked == FALSE) {\n      if (c->icon_fetch_uid == 0 || c->icon_fetch_size != size ||\n          c->icon_fetch_scale != scale) {\n        char *class_lower = g_utf8_strdown(c->class, -1);\n        c->icon_fetch_uid = rofi_icon_fetcher_query(class_lower, size);\n        g_free(class_lower);\n        c->icon_fetch_size = size;\n        c->icon_fetch_scale = scale;\n      }\n      c->icon_theme_checked =\n          rofi_icon_fetcher_get_ex(c->icon_fetch_uid, &(c->icon));\n      if (c->icon) {\n        cairo_surface_reference(c->icon);\n      }\n    }\n    if (c->icon_theme_checked == TRUE && c->icon == NULL &&\n        c->icon_checked == FALSE) {\n      c->icon = get_net_wm_icon(rmpd->ids->array[selected_line], size);\n      c->icon_checked = TRUE;\n    }\n  }\n  c->icon_fetch_size = size;\n  c->icon_fetch_scale = scale;\n  return c->icon;\n}\n\n#include \"mode-private.h\"\nMode window_mode = {.name = \"window\",\n                    .cfg_name_key = \"display-window\",\n                    ._init = window_mode_init,\n                    ._get_num_entries = window_mode_get_num_entries,\n                    ._result = window_mode_result,\n                    ._destroy = window_mode_destroy,\n                    ._token_match = window_match,\n                    ._get_display_value = _get_display_value,\n                    ._get_icon = _get_icon,\n                    ._get_completion = NULL,\n                    ._preprocess_input = NULL,\n                    .private_data = NULL,\n                    .free = NULL,\n                    .type = MODE_TYPE_SWITCHER};\nMode window_mode_cd = {.name = \"windowcd\",\n                       .cfg_name_key = \"display-windowcd\",\n                       ._init = window_mode_init_cd,\n                       ._get_num_entries = window_mode_get_num_entries,\n                       ._result = window_mode_result,\n                       ._destroy = window_mode_destroy,\n                       ._token_match = window_match,\n                       ._get_display_value = _get_display_value,\n                       ._get_icon = _get_icon,\n                       ._get_completion = NULL,\n                       ._preprocess_input = NULL,\n                       .private_data = NULL,\n                       .free = NULL,\n                       .type = MODE_TYPE_SWITCHER};\n\n#endif // WINDOW_MODE\n"
  },
  {
    "path": "source/rofi-icon-fetcher.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this Helper. */\n#define G_LOG_DOMAIN \"Helpers.IconFetcher\"\n\n#include \"config.h\"\n#include <stdlib.h>\n\n#include \"helper.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi-types.h\"\n#include \"settings.h\"\n#include <cairo.h>\n#include <pango/pangocairo.h>\n\n#include \"display.h\"\n#include \"keyb.h\"\n#include \"view.h\"\n\n#include \"nkutils-enum.h\"\n#include \"nkutils-xdg-theme.h\"\n\n#include <stdint.h>\n\n#include \"helper.h\"\n#include <gdk-pixbuf/gdk-pixbuf.h>\n\n/** Desktop entry specifying the thumbnailer. */\n#define THUMBNAILER_ENTRY_GROUP \"Thumbnailer Entry\"\n/** Extension used for the thumbnailer. */\n#define THUMBNAILER_EXTENSION \".thumbnailer\"\n\ntypedef struct {\n  // Context for icon-themes.\n  NkXdgThemeContext *xdg_context;\n\n  // On name.\n  GHashTable *icon_cache;\n  // On uid.\n  GHashTable *icon_cache_uid;\n\n  // list extensions\n  GList *supported_extensions;\n  uint32_t last_uid;\n\n  // thumbnailers per mime-types hashmap\n  GHashTable *thumbnailers;\n} IconFetcher;\n\ntypedef struct {\n  char *name;\n  GList *sizes;\n} IconFetcherNameEntry;\n\ntypedef struct {\n  thread_state state;\n\n  GCond *cond;\n  GMutex *mutex;\n  unsigned int *acount;\n\n  uint32_t uid;\n  int wsize;\n  int hsize;\n  guint scale;\n  cairo_surface_t *surface;\n  gboolean query_done;\n  gboolean query_started;\n\n  IconFetcherNameEntry *entry;\n} IconFetcherEntry;\n\n// Free method.\nstatic void rofi_icon_fetch_entry_free(gpointer data);\n/**\n * The icon fetcher internal state.\n */\nIconFetcher *rofi_icon_fetcher_data = NULL;\n\nstatic void rofi_icon_fetcher_load_thumbnailers(const gchar *path) {\n  gchar *thumb_path = g_build_filename(path, \"thumbnailers\", NULL);\n\n  GDir *dir = g_dir_open(thumb_path, 0, NULL);\n\n  if (!dir) {\n    g_free(thumb_path);\n    return;\n  }\n\n  const gchar *dirent;\n\n  while ((dirent = g_dir_read_name(dir))) {\n    if (!g_str_has_suffix(dirent, THUMBNAILER_EXTENSION))\n      continue;\n\n    gchar *filename = g_build_filename(thumb_path, dirent, NULL);\n    GKeyFile *key_file = g_key_file_new();\n    GError *error = NULL;\n\n    if (!g_key_file_load_from_file(key_file, filename, 0, &error)) {\n      g_warning(\"Error loading thumbnailer %s: %s\", filename, error->message);\n      g_error_free(error);\n    } else {\n      gchar *command = g_key_file_get_string(key_file, THUMBNAILER_ENTRY_GROUP,\n                                             \"Exec\", NULL);\n      gchar **mime_types = g_key_file_get_string_list(\n          key_file, THUMBNAILER_ENTRY_GROUP, \"MimeType\", NULL, NULL);\n\n      if (mime_types && command) {\n        guint i;\n        for (i = 0; mime_types[i] != NULL; i++) {\n          if (!g_hash_table_lookup(rofi_icon_fetcher_data->thumbnailers,\n                                   mime_types[i])) {\n            g_info(\"Loading thumbnailer %s for mimetype %s\", filename,\n                   mime_types[i]);\n            g_hash_table_insert(rofi_icon_fetcher_data->thumbnailers,\n                                g_strdup(mime_types[i]), g_strdup(command));\n          }\n        }\n      }\n\n      if (mime_types)\n        g_strfreev(mime_types);\n      if (command)\n        g_free(command);\n    }\n\n    g_key_file_free(key_file);\n    g_free(filename);\n  }\n\n  g_dir_close(dir);\n  g_free(thumb_path);\n}\n\nstatic gchar **setup_thumbnailer_command(const gchar *command,\n                                         const gchar *filename,\n                                         const gchar *encoded_uri,\n                                         const gchar *output_path, int size) {\n  gchar **command_parts = g_strsplit(command, \" \", 0);\n  guint command_parts_count = g_strv_length(command_parts);\n\n  gchar **command_args = NULL;\n\n  if (command_parts) {\n    command_args = g_malloc0(sizeof(gchar *) * (command_parts_count + 3 + 1));\n\n    // set process niceness value to 19 (low priority)\n    guint current_index = 0;\n\n    command_args[current_index++] = g_strdup(\"nice\");\n    command_args[current_index++] = g_strdup(\"-n\");\n    command_args[current_index++] = g_strdup(\"19\");\n\n    // add executable and arguments of the thumbnailer to the list\n    guint i;\n    for (i = 0; command_parts[i] != NULL; i++) {\n      if (strcmp(command_parts[i], \"%i\") == 0) {\n        command_args[current_index++] = g_strdup(filename);\n      } else if (strcmp(command_parts[i], \"%u\") == 0) {\n        command_args[current_index++] = g_strdup(encoded_uri);\n      } else if (strcmp(command_parts[i], \"%o\") == 0) {\n        command_args[current_index++] = g_strdup(output_path);\n      } else if (strcmp(command_parts[i], \"%s\") == 0) {\n        command_args[current_index++] = g_strdup_printf(\"%d\", size);\n      } else {\n        command_args[current_index++] = g_strdup(command_parts[i]);\n      }\n    }\n\n    command_args[current_index++] = NULL;\n\n    g_strfreev(command_parts);\n  }\n\n  return command_args;\n}\n\nstatic gboolean exec_thumbnailer_command(gchar **command_args) {\n  // launch and wait thumbnailers process\n  gint wait_status;\n  GError *error = NULL;\n\n  gboolean spawned = g_spawn_sync(NULL, command_args, NULL,\n                                  G_SPAWN_DEFAULT | G_SPAWN_SEARCH_PATH, NULL,\n                                  NULL, NULL, NULL, &wait_status, &error);\n\n  if (spawned) {\n    return g_spawn_check_wait_status(wait_status, NULL);\n  } else {\n    g_warning(\"Error calling thumbnailer: %s\", error->message);\n    g_error_free(error);\n\n    return FALSE;\n  }\n}\n\nstatic gboolean rofi_icon_fetcher_create_thumbnail(const gchar *mime_type,\n                                                   const gchar *filename,\n                                                   const gchar *encoded_uri,\n                                                   const gchar *output_path,\n                                                   int size) {\n  gboolean thumbnail_created = FALSE;\n\n  gchar *command =\n      g_hash_table_lookup(rofi_icon_fetcher_data->thumbnailers, mime_type);\n\n  if (!command) {\n    return thumbnail_created;\n  }\n\n  // split command string to isolate arguments and expand them in a list\n  gchar **command_args = setup_thumbnailer_command(\n      command, filename, encoded_uri, output_path, size);\n\n  if (command_args) {\n    thumbnail_created = exec_thumbnailer_command(command_args);\n    g_strfreev(command_args);\n  }\n\n  return thumbnail_created;\n}\n\nstatic void rofi_icon_fetch_thread_pool_entry_remove(gpointer data) {\n  IconFetcherEntry *entry = (IconFetcherEntry *)data;\n  // Mark it in a way it should be re-fetched on next query?\n  entry->query_started = FALSE;\n}\n\nstatic void rofi_icon_fetch_entry_free(gpointer data) {\n  IconFetcherNameEntry *entry = (IconFetcherNameEntry *)data;\n\n  // Free name/key.\n  g_free(entry->name);\n\n  for (GList *iter = g_list_first(entry->sizes); iter;\n       iter = g_list_next(iter)) {\n    IconFetcherEntry *sentry = (IconFetcherEntry *)(iter->data);\n\n    cairo_surface_destroy(sentry->surface);\n    g_free(sentry);\n  }\n\n  g_list_free(entry->sizes);\n  g_free(entry);\n}\n\nvoid rofi_icon_fetcher_init(void) {\n  g_assert(rofi_icon_fetcher_data == NULL);\n\n  static const gchar *const icon_fallback_themes[] = {\"Adwaita\", \"gnome\", NULL};\n  const char *themes[2] = {config.icon_theme, NULL};\n\n  rofi_icon_fetcher_data = g_malloc0(sizeof(IconFetcher));\n\n  rofi_icon_fetcher_data->xdg_context =\n      nk_xdg_theme_context_new(icon_fallback_themes, NULL);\n  nk_xdg_theme_preload_themes_icon(rofi_icon_fetcher_data->xdg_context, themes);\n\n  rofi_icon_fetcher_data->icon_cache_uid =\n      g_hash_table_new(g_direct_hash, g_direct_equal);\n  rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full(\n      g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free);\n\n  GSList *l = gdk_pixbuf_get_formats();\n  for (GSList *li = l; li != NULL; li = g_slist_next(li)) {\n    gchar **exts =\n        gdk_pixbuf_format_get_extensions((GdkPixbufFormat *)li->data);\n\n    for (unsigned int i = 0; exts && exts[i]; i++) {\n      rofi_icon_fetcher_data->supported_extensions =\n          g_list_append(rofi_icon_fetcher_data->supported_extensions, exts[i]);\n      g_info(\"Add image extension: %s\", exts[i]);\n      exts[i] = NULL;\n    }\n\n    g_free(exts);\n  }\n  g_slist_free(l);\n\n  // load available thumbnailers from system dirs and user dir\n  rofi_icon_fetcher_data->thumbnailers = g_hash_table_new_full(\n      g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free);\n\n  const gchar *const *system_data_dirs = g_get_system_data_dirs();\n  const gchar *user_data_dir = g_get_user_data_dir();\n\n  rofi_icon_fetcher_load_thumbnailers(user_data_dir);\n\n  guint i;\n  for (i = 0; system_data_dirs[i] != NULL; i++) {\n    rofi_icon_fetcher_load_thumbnailers(system_data_dirs[i]);\n  }\n}\n\nstatic void free_wrapper(gpointer data, G_GNUC_UNUSED gpointer user_data) {\n  g_free(data);\n}\n\nvoid rofi_icon_fetcher_destroy(void) {\n  if (rofi_icon_fetcher_data == NULL) {\n    return;\n  }\n\n  g_hash_table_unref(rofi_icon_fetcher_data->thumbnailers);\n\n  nk_xdg_theme_context_free(rofi_icon_fetcher_data->xdg_context);\n\n  g_hash_table_unref(rofi_icon_fetcher_data->icon_cache_uid);\n  g_hash_table_unref(rofi_icon_fetcher_data->icon_cache);\n\n  g_list_foreach(rofi_icon_fetcher_data->supported_extensions, free_wrapper,\n                 NULL);\n  g_list_free(rofi_icon_fetcher_data->supported_extensions);\n  g_free(rofi_icon_fetcher_data);\n}\n\n/*\n * _rofi_icon_fetcher_get_icon_surface and alpha_mult\n * are inspired by gdk_cairo_set_source_pixbuf\n * GDK is:\n *     Copyright (C) 2011-2018 Red Hat, Inc.\n */\n#if G_BYTE_ORDER == G_LITTLE_ENDIAN\n/** Location of red byte */\n#define RED_BYTE 2\n/** Location of green byte */\n#define GREEN_BYTE 1\n/** Location of blue byte */\n#define BLUE_BYTE 0\n/** Location of alpha byte */\n#define ALPHA_BYTE 3\n#else\n/** Location of red byte */\n#define RED_BYTE 1\n/** Location of green byte */\n#define GREEN_BYTE 2\n/** Location of blue byte */\n#define BLUE_BYTE 3\n/** Location of alpha byte */\n#define ALPHA_BYTE 0\n#endif\n\nstatic inline guchar alpha_mult(guchar c, guchar a) {\n  guint16 t;\n  switch (a) {\n  case 0xff:\n    return c;\n  case 0x00:\n    return 0x00;\n  default:\n    t = c * a + 0x7f;\n    return ((t >> 8) + t) >> 8;\n  }\n}\n\nstatic cairo_surface_t *\nrofi_icon_fetcher_get_surface_from_pixbuf(GdkPixbuf *pixbuf) {\n  gint width, height;\n  const guchar *pixels;\n  gint stride;\n  gboolean alpha;\n\n  if (pixbuf == NULL) {\n    return NULL;\n  }\n\n  width = gdk_pixbuf_get_width(pixbuf);\n  height = gdk_pixbuf_get_height(pixbuf);\n  pixels = gdk_pixbuf_read_pixels(pixbuf);\n  stride = gdk_pixbuf_get_rowstride(pixbuf);\n  alpha = gdk_pixbuf_get_has_alpha(pixbuf);\n\n  cairo_surface_t *surface = NULL;\n\n  gint cstride;\n  guint lo, o;\n  guchar a = 0xff;\n  const guchar *pixels_end, *line;\n  guchar *cpixels;\n\n  pixels_end = pixels + height * stride;\n  o = alpha ? 4 : 3;\n  lo = o * width;\n\n  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);\n  cpixels = cairo_image_surface_get_data(surface);\n  cstride = cairo_image_surface_get_stride(surface);\n\n  cairo_surface_flush(surface);\n  while (pixels < pixels_end) {\n    line = pixels;\n    const guchar *line_end = line + lo;\n    guchar *cline = cpixels;\n\n    while (line < line_end) {\n      if (alpha) {\n        a = line[3];\n      }\n      cline[RED_BYTE] = alpha_mult(line[0], a);\n      cline[GREEN_BYTE] = alpha_mult(line[1], a);\n      cline[BLUE_BYTE] = alpha_mult(line[2], a);\n      cline[ALPHA_BYTE] = a;\n\n      line += o;\n      cline += 4;\n    }\n\n    pixels += stride;\n    cpixels += cstride;\n  }\n  cairo_surface_mark_dirty(surface);\n  cairo_surface_flush(surface);\n\n  return surface;\n}\n\ngboolean rofi_icon_fetcher_file_is_image(const char *const path) {\n  if (path == NULL) {\n    return FALSE;\n  }\n  const char *suf = strrchr(path, '.');\n  if (suf == NULL) {\n    return FALSE;\n  }\n  suf++;\n\n  for (GList *iter = rofi_icon_fetcher_data->supported_extensions; iter != NULL;\n       iter = g_list_next(iter)) {\n    if (g_ascii_strcasecmp(iter->data, suf) == 0) {\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n\n// build thumbnail's path using md5 hash of an entry name\nstatic gchar *rofi_icon_fetcher_get_thumbnail(gchar *name, int requested_size,\n                                              int *thumb_size) {\n  // calc entry_name md5 hash\n  GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);\n  g_checksum_update(checksum, (guchar *)name, -1);\n  const gchar *md5_hex = g_checksum_get_string(checksum);\n\n  // determine thumbnail folder based on the request size\n  const gchar *cache_dir = g_get_user_cache_dir();\n  gchar *thumb_dir;\n  gchar *thumb_path;\n\n  if (requested_size <= 128) {\n    *thumb_size = 128;\n    thumb_dir = g_strconcat(cache_dir, \"/thumbnails/normal/\", NULL);\n    thumb_path =\n        g_strconcat(cache_dir, \"/thumbnails/normal/\", md5_hex, \".png\", NULL);\n  } else if (requested_size <= 256) {\n    *thumb_size = 256;\n    thumb_dir = g_strconcat(cache_dir, \"/thumbnails/large/\", NULL);\n    thumb_path =\n        g_strconcat(cache_dir, \"/thumbnails/large/\", md5_hex, \".png\", NULL);\n  } else if (requested_size <= 512) {\n    *thumb_size = 512;\n    thumb_dir = g_strconcat(cache_dir, \"/thumbnails/x-large/\", NULL);\n    thumb_path =\n        g_strconcat(cache_dir, \"/thumbnails/x-large/\", md5_hex, \".png\", NULL);\n  } else {\n    *thumb_size = 1024;\n    thumb_dir = g_strconcat(cache_dir, \"/thumbnails/xx-large/\", NULL);\n    thumb_path =\n        g_strconcat(cache_dir, \"/thumbnails/xx-large/\", md5_hex, \".png\", NULL);\n  }\n\n  // create thumbnail directory if it does not exist\n  g_mkdir_with_parents(thumb_dir, 0700);\n\n  g_free(thumb_dir);\n  g_checksum_free(checksum);\n\n  return thumb_path;\n}\n\n// retrieves icon key from a .desktop file\nstatic gchar *rofi_icon_fetcher_get_desktop_icon(const gchar *file_path) {\n  GKeyFile *kf = g_key_file_new();\n  GError *key_error = NULL;\n  gchar *icon_key = NULL;\n\n  gboolean res = g_key_file_load_from_file(kf, file_path, 0, &key_error);\n\n  if (res) {\n    icon_key = g_key_file_get_string(kf, \"Desktop Entry\", \"Icon\", NULL);\n  } else {\n    g_debug(\"Failed to parse desktop file %s because: %s.\", file_path,\n            key_error->message);\n\n    g_error_free(key_error);\n  }\n\n  g_key_file_free(kf);\n\n  return icon_key;\n}\n\nstatic void rofi_icon_fetcher_worker(thread_state *sdata,\n                                     G_GNUC_UNUSED gpointer user_data) {\n  g_debug(\"starting up icon fetching thread.\");\n  // as long as dr->icon is updated atomicly.. (is a pointer write atomic?)\n  // this should be fine running in another thread.\n  IconFetcherEntry *sentry = (IconFetcherEntry *)sdata;\n  const gchar *themes[] = {config.icon_theme, NULL};\n\n  const gchar *icon_path;\n  gchar *icon_path_ = NULL;\n\n  if (g_str_has_prefix(sentry->entry->name, \"thumbnail://\")) {\n    // remove uri thumbnail prefix from entry name\n    gchar *entry_name = &sentry->entry->name[12];\n\n    if (strcmp(entry_name, \"\") == 0) {\n      sentry->query_done = TRUE;\n      rofi_view_reload();\n      return;\n    }\n\n    // use custom user command to generate the thumbnail\n    if (config.preview_cmd != NULL) {\n      int requested_size = MAX(sentry->wsize, sentry->hsize);\n      int thumb_size;\n\n      icon_path = icon_path_ = rofi_icon_fetcher_get_thumbnail(\n          entry_name, requested_size, &thumb_size);\n\n      if (!g_file_test(icon_path, G_FILE_TEST_EXISTS)) {\n        char **command_args = NULL;\n        int argsv = 0;\n        gchar *size_str = g_strdup_printf(\"%d\", thumb_size);\n\n        helper_parse_setup(config.preview_cmd, &command_args, &argsv, \"{input}\",\n                           entry_name, \"{output}\", icon_path_, \"{size}\",\n                           size_str, NULL);\n\n        g_free(size_str);\n\n        if (command_args) {\n          exec_thumbnailer_command(command_args);\n          g_strfreev(command_args);\n        }\n      }\n    } else if (g_path_is_absolute(entry_name)) {\n      // if the entry name is an absolute path try to fetch its thumbnail\n      if (g_str_has_suffix(entry_name, \".desktop\")) {\n        // if the entry is a .desktop file try to read its icon key\n        gchar *icon_key = rofi_icon_fetcher_get_desktop_icon(entry_name);\n\n        if (icon_key == NULL || strlen(icon_key) == 0) {\n          // no icon in .desktop file, fallback on mimetype icon (text/plain)\n          icon_path = icon_path_ = nk_xdg_theme_get_icon(\n              rofi_icon_fetcher_data->xdg_context, themes, NULL, \"text-plain\",\n              MIN(sentry->wsize, sentry->hsize), 1, TRUE);\n\n          g_free(icon_key);\n        } else if (g_path_is_absolute(icon_key)) {\n          // icon in .desktop file is an absolute path to an image\n          icon_path = icon_path_ = icon_key;\n        } else {\n          // icon in .desktop file is a standard icon name\n          icon_path = icon_path_ = nk_xdg_theme_get_icon(\n              rofi_icon_fetcher_data->xdg_context, themes, NULL, icon_key,\n              MIN(sentry->wsize, sentry->hsize), 1, TRUE);\n\n          g_free(icon_key);\n        }\n      } else {\n        // build encoded uri string from absolute file path\n        gchar *encoded_uri = g_filename_to_uri(entry_name, NULL, NULL);\n        int requested_size = MAX(sentry->wsize, sentry->hsize);\n        int thumb_size;\n\n        // look for file thumbnail in appropriate folder based on requested size\n        icon_path = icon_path_ = rofi_icon_fetcher_get_thumbnail(\n            encoded_uri, requested_size, &thumb_size);\n\n        if (!g_file_test(icon_path, G_FILE_TEST_EXISTS)) {\n          // try to generate thumbnail\n          char *content_type = g_content_type_guess(entry_name, NULL, 0, NULL);\n          char *mime_type = g_content_type_get_mime_type(content_type);\n\n          if (mime_type) {\n            gboolean created = rofi_icon_fetcher_create_thumbnail(\n                mime_type, entry_name, encoded_uri, icon_path_, thumb_size);\n\n            if (!created) {\n              // replace forward slashes with minus sign to get the icon's name\n              int index = 0;\n\n              while (mime_type[index]) {\n                if (mime_type[index] == '/')\n                  mime_type[index] = '-';\n                index++;\n              }\n\n              g_free(icon_path_);\n\n              // try to fetch the mime-type icon\n              icon_path = icon_path_ = nk_xdg_theme_get_icon(\n                  rofi_icon_fetcher_data->xdg_context, themes, NULL, mime_type,\n                  MIN(sentry->wsize, sentry->hsize), 1, TRUE);\n            }\n\n            g_free(mime_type);\n            g_free(content_type);\n          }\n        }\n\n        g_free(encoded_uri);\n      }\n    }\n\n    // no suitable icon or thumbnail was found\n    if (icon_path_ == NULL || !g_file_test(icon_path, G_FILE_TEST_EXISTS)) {\n      sentry->query_done = TRUE;\n      rofi_view_reload();\n      return;\n    }\n  } else if (g_path_is_absolute(sentry->entry->name)) {\n    icon_path = sentry->entry->name;\n  } else if (g_str_has_prefix(sentry->entry->name, \"<span\")) {\n    cairo_surface_t *surface = cairo_image_surface_create(\n        CAIRO_FORMAT_ARGB32, sentry->wsize, sentry->hsize);\n    cairo_t *cr = cairo_create(surface);\n    PangoLayout *layout = pango_cairo_create_layout(cr);\n    pango_layout_set_markup(layout, sentry->entry->name, -1);\n\n    int width, height;\n    pango_layout_get_size(layout, &width, &height);\n    double ws = sentry->wsize / ((double)width / PANGO_SCALE);\n    double wh = sentry->hsize / ((double)height / PANGO_SCALE);\n    double scale = MIN(ws, wh);\n\n    cairo_move_to(\n        cr, (sentry->wsize - ((double)width / PANGO_SCALE) * scale) / 2.0,\n        (sentry->hsize - ((double)height / PANGO_SCALE) * scale) / 2.0);\n    cairo_scale(cr, scale, scale);\n    pango_cairo_update_layout(cr, layout);\n    pango_layout_get_size(layout, &width, &height);\n    pango_cairo_show_layout(cr, layout);\n    g_object_unref(layout);\n    cairo_destroy(cr);\n    sentry->surface = surface;\n    sentry->query_done = TRUE;\n    rofi_view_reload();\n    return;\n\n  } else {\n    icon_path = icon_path_ = nk_xdg_theme_get_icon(\n        rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name,\n        MIN(sentry->wsize, sentry->hsize), sentry->scale, TRUE);\n    if (icon_path_ == NULL) {\n      g_debug(\"failed to get icon %s(%dx%d): n/a\", sentry->entry->name,\n              sentry->wsize, sentry->hsize);\n\n      const char *ext = g_strrstr(sentry->entry->name, \".\");\n      if (ext) {\n        const char *exts2[2] = {ext, NULL};\n        icon_path = icon_path_ =\n            helper_get_theme_path(sentry->entry->name, exts2, NULL);\n      }\n      if (icon_path_ == NULL) {\n        sentry->query_done = TRUE;\n        rofi_view_reload();\n        return;\n      }\n    } else {\n      g_debug(\"found icon %s(%dx%d): %s\", sentry->entry->name, sentry->wsize,\n              sentry->hsize, icon_path);\n    }\n  }\n  cairo_surface_t *icon_surf = NULL;\n\n#if 0 // unsure why added in past?\n  const char *suf = strrchr(icon_path, '.');\n  if (suf == NULL) {\n    sentry->query_done = TRUE;\n    g_free(icon_path_);\n    rofi_view_reload();\n    return;\n  }\n#endif\n\n  int width = sentry->wsize, height = sentry->hsize;\n  if (width > 0)\n    width *= sentry->scale;\n  if (height > 0)\n    height *= sentry->scale;\n\n  GError *error = NULL;\n  GdkPixbuf *pb =\n      gdk_pixbuf_new_from_file_at_scale(icon_path, width, height, TRUE, &error);\n\n  /*\n   * The GIF codec throws GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION if it's closed\n   * without decoding all the frames. Since gdk_pixbuf_new_from_file_at_scale\n   * only decodes the first frame, this specific error needs to be ignored.\n   */\n  if (error != NULL && g_error_matches(error, GDK_PIXBUF_ERROR,\n                                       GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION)) {\n    g_clear_error(&error);\n  }\n\n  if (error != NULL) {\n    g_warning(\"Failed to load image: |%s| %d %d %s (%p)\", icon_path,\n              sentry->wsize, sentry->hsize, error->message, (void *)pb);\n    g_error_free(error);\n    if (pb) {\n      g_object_unref(pb);\n    }\n  } else {\n    icon_surf = rofi_icon_fetcher_get_surface_from_pixbuf(pb);\n    g_object_unref(pb);\n  }\n\n  sentry->surface = icon_surf;\n  g_free(icon_path_);\n  sentry->query_done = TRUE;\n  rofi_view_reload();\n}\n\nuint32_t rofi_icon_fetcher_query_advanced(const char *name, const int wsize,\n                                          const int hsize) {\n  g_debug(\"Query: %s(%dx%d)\", name, wsize, hsize);\n  IconFetcherNameEntry *entry =\n      g_hash_table_lookup(rofi_icon_fetcher_data->icon_cache, name);\n  if (entry == NULL) {\n    entry = g_new0(IconFetcherNameEntry, 1);\n    entry->name = g_strdup(name);\n    g_hash_table_insert(rofi_icon_fetcher_data->icon_cache, entry->name, entry);\n  }\n  IconFetcherEntry *sentry;\n  const guint scale = display_scale();\n  for (GList *iter = g_list_first(entry->sizes); iter;\n       iter = g_list_next(iter)) {\n    sentry = iter->data;\n    if (sentry->wsize == wsize && sentry->hsize == hsize &&\n        sentry->scale == scale) {\n      if (!sentry->query_started) {\n        g_thread_pool_push(tpool, sentry, NULL);\n      }\n      return sentry->uid;\n    }\n  }\n\n  // Not found.\n  sentry = g_new0(IconFetcherEntry, 1);\n  sentry->uid = ++(rofi_icon_fetcher_data->last_uid);\n  sentry->wsize = wsize;\n  sentry->hsize = hsize;\n  sentry->scale = scale;\n  sentry->entry = entry;\n  sentry->query_done = FALSE;\n  sentry->query_started = TRUE;\n  sentry->surface = NULL;\n\n  entry->sizes = g_list_prepend(entry->sizes, sentry);\n  g_hash_table_insert(rofi_icon_fetcher_data->icon_cache_uid,\n                      GINT_TO_POINTER(sentry->uid), sentry);\n\n  // Push into fetching queue.\n  sentry->state.callback = rofi_icon_fetcher_worker;\n  sentry->state.free = rofi_icon_fetch_thread_pool_entry_remove;\n  sentry->state.priority = G_PRIORITY_LOW;\n  g_thread_pool_push(tpool, sentry, NULL);\n\n  return sentry->uid;\n}\nuint32_t rofi_icon_fetcher_query(const char *name, const int size) {\n  g_debug(\"Query: %s(%d)\", name, size);\n  IconFetcherNameEntry *entry =\n      g_hash_table_lookup(rofi_icon_fetcher_data->icon_cache, name);\n  if (entry == NULL) {\n    entry = g_new0(IconFetcherNameEntry, 1);\n    entry->name = g_strdup(name);\n    g_hash_table_insert(rofi_icon_fetcher_data->icon_cache, entry->name, entry);\n  }\n  IconFetcherEntry *sentry;\n  const guint scale = display_scale();\n  for (GList *iter = g_list_first(entry->sizes); iter;\n       iter = g_list_next(iter)) {\n    sentry = iter->data;\n    if (sentry->wsize == size && sentry->hsize == size &&\n        sentry->scale == scale) {\n      if (!sentry->query_started) {\n        g_thread_pool_push(tpool, sentry, NULL);\n      }\n      return sentry->uid;\n    }\n  }\n\n  // Not found.\n  sentry = g_new0(IconFetcherEntry, 1);\n  sentry->uid = ++(rofi_icon_fetcher_data->last_uid);\n  sentry->wsize = size;\n  sentry->hsize = size;\n  sentry->scale = scale;\n  sentry->entry = entry;\n  sentry->query_done = FALSE;\n  sentry->query_started = TRUE;\n  sentry->surface = NULL;\n\n  entry->sizes = g_list_prepend(entry->sizes, sentry);\n  g_hash_table_insert(rofi_icon_fetcher_data->icon_cache_uid,\n                      GINT_TO_POINTER(sentry->uid), sentry);\n\n  // Push into fetching queue.\n  sentry->state.callback = rofi_icon_fetcher_worker;\n  sentry->state.free = rofi_icon_fetch_thread_pool_entry_remove;\n  sentry->state.priority = G_PRIORITY_LOW;\n  g_thread_pool_push(tpool, sentry, NULL);\n\n  return sentry->uid;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(const uint32_t uid) {\n  IconFetcherEntry *sentry = g_hash_table_lookup(\n      rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER(uid));\n  if (sentry) {\n    return sentry->surface;\n  }\n  g_warning(\"Querying an non-existing uid\");\n  return NULL;\n}\n\ngboolean rofi_icon_fetcher_get_ex(const uint32_t uid,\n                                  cairo_surface_t **surface) {\n  IconFetcherEntry *sentry = g_hash_table_lookup(\n      rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER(uid));\n  *surface = NULL;\n  if (sentry) {\n    *surface = sentry->surface;\n    return sentry->query_done;\n  }\n  g_warning(\"Querying an non-existing uid\");\n  return FALSE;\n}\n"
  },
  {
    "path": "source/rofi-types.c",
    "content": "#include \"rofi-types.h\"\n\n/**\n * Name of the property type\n */\nconst char *const PropertyTypeName[P_NUM_TYPES] = {\n    /** Integer */\n    \"Integer\",\n    /** Double */\n    \"Double\",\n    /** String */\n    \"String\",\n    /** Boolean */\n    \"Boolean\",\n    /** Color */\n    \"Color\",\n    /** Image */\n    \"Image\",\n    /** Padding */\n    \"Padding\",\n    /** Link to global setting */\n    \"Reference\",\n    /** Position */\n    \"Position\",\n    /** Highlight */\n    \"Highlight\",\n    /** List */\n    \"List\",\n    /** Orientation */\n    \"Orientation\",\n    /** Cursor */\n    \"Cursor\",\n    /** Inherit */\n    \"Inherit\",\n};\n"
  },
  {
    "path": "source/rofi.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** Log domain */\n#define G_LOG_DOMAIN \"Rofi\"\n\n#include \"config.h\"\n#include <errno.h>\n#include <gmodule.h>\n#include <locale.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <sysexits.h>\n#include <time.h>\n#include <unistd.h>\n\n#include <glib-unix.h>\n\n#ifdef USE_NK_GIT_VERSION\n#include \"nkutils-git-version.h\"\n#ifdef NK_GIT_VERSION\n#define GIT_VERSION NK_GIT_VERSION\n#endif\n#endif\n\n#include \"resources.h\"\n\n#include \"display.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n\n#include \"helper.h\"\n#include \"mode.h\"\n#include \"modes/modes.h\"\n#include \"widgets/textbox.h\"\n#include \"xrmoptions.h\"\n\n#include \"view-internal.h\"\n#include \"view.h\"\n\n#include \"rofi-icon-fetcher.h\"\n#include \"theme.h\"\n\n#include \"timings.h\"\n\n#ifdef ENABLE_WAYLAND\n#include <wayland-version.h>\n\n#endif\n\n// Limit the max stdin input to 4gb.\n#define ROFI_MAX_DMENU_INPUT UINT32_MAX\n\n/** Location of pidfile for this instance. */\nchar *pidfile = NULL;\n/** Location of Cache directory. */\nconst char *cache_dir = NULL;\n/** if the cache_dir string is allocated, keep pointer here so it can be freed.\n */\nchar *cache_dir_alloc = NULL;\n\n/** List of error messages.*/\nGList *list_of_error_msgs = NULL;\n/** List of warning messages for the user.*/\nGList *list_of_warning_msgs = NULL;\n\nstatic void rofi_collectmodes_destroy(void);\nvoid rofi_add_error_message(GString *str) {\n  list_of_error_msgs = g_list_append(list_of_error_msgs, str);\n}\nvoid rofi_clear_error_messages(void) {\n  if (list_of_error_msgs) {\n    for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;\n         iter = g_list_next(iter)) {\n      g_string_free((GString *)iter->data, TRUE);\n    }\n    g_list_free(list_of_error_msgs);\n    list_of_error_msgs = NULL;\n  }\n}\nvoid rofi_add_warning_message(GString *str) {\n  list_of_warning_msgs = g_list_append(list_of_warning_msgs, str);\n}\nvoid rofi_clear_warning_messages(void) {\n  if (list_of_warning_msgs) {\n    for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;\n         iter = g_list_next(iter)) {\n      g_string_free((GString *)iter->data, TRUE);\n    }\n    g_list_free(list_of_warning_msgs);\n    list_of_warning_msgs = NULL;\n  }\n}\n\n/** Path to the configuration file */\nG_MODULE_EXPORT char *config_path = NULL;\n/** Path to the configuration file in the new format */\n/** Array holding all activated modes. */\nMode **modes = NULL;\n\n/**  List of (possibly uninitialized) modes */\nMode **available_modes = NULL;\n/** Length of #num_available_modes */\nunsigned int num_available_modes = 0;\n/** Number of activated modes in #modes array */\nunsigned int num_modes = 0;\n/** Current selected mode */\nunsigned int curr_mode = 0;\n\n/** Handle to NkBindings object for input devices. */\nNkBindings *bindings = NULL;\n\n/** Switches to TRUE when display is set up and ready */\ngboolean display_setup_success = FALSE;\n\n/** Glib main loop. */\nGMainLoop *main_loop = NULL;\n\n/** Flag indicating we are in dmenu mode. */\nint rofi_is_in_dmenu_mode = FALSE;\n/** Rofi's return code */\nint return_code = EXIT_SUCCESS;\n\nvoid process_result(RofiViewState *state);\n\nvoid rofi_set_return_code(int code) { return_code = code; }\n\nunsigned int rofi_get_num_enabled_modes(void) { return num_modes; }\n\nconst Mode *rofi_get_mode(unsigned int index) { return modes[index]; }\n\nint mode_lookup(const char *name) {\n  for (unsigned int i = 0; i < num_modes; i++) {\n    if (strcmp(mode_get_name(modes[i]), name) == 0) {\n      return i;\n    }\n  }\n  return -1;\n}\n/**\n * @param name Name of the mode to lookup.\n *\n * Find the index of the mode with name.\n *\n * @returns index of the mode in modes, -1 if not found.\n */\nstatic const Mode *mode_available_lookup(const char *name) {\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    if (strcmp(mode_get_name(available_modes[i]), name) == 0) {\n      return available_modes[i];\n    }\n  }\n  return NULL;\n}\n\n/**\n * Teardown the gui.\n */\nstatic void teardown(int pfd) {\n  g_debug(\"Teardown\");\n  // Cleanup font setup.\n  textbox_cleanup();\n\n  display_early_cleanup();\n\n  // Cleanup view\n  rofi_view_cleanup();\n\n  // Cleanup pid file.\n  remove_pid_file(pfd);\n}\nstatic void run_mode_index(ModeMode mode) {\n  // Otherwise check if requested mode is enabled.\n  for (unsigned int i = 0; i < num_modes; i++) {\n    if (!mode_init(modes[i])) {\n      GString *str = g_string_new(\"Failed to initialize the mode: \");\n      g_string_append(str, mode_get_name(modes[i]));\n      g_string_append(str, \"\\n\");\n\n      rofi_view_error_dialog(str->str, ERROR_MSG_MARKUP);\n      g_string_free(str, FALSE);\n      break;\n    }\n  }\n  // Error dialog must have been created.\n  if (rofi_view_get_active() != NULL) {\n    return;\n  }\n  curr_mode = mode;\n  RofiViewState *state =\n      rofi_view_create(modes[mode], config.filter, 0, process_result);\n\n  // User can pre-select a row.\n  if (find_arg(\"-selected-row\") >= 0) {\n    unsigned int sr = 0;\n    find_arg_uint(\"-selected-row\", &(sr));\n    rofi_view_set_selected_line(state, sr);\n  }\n  if (state) {\n    rofi_view_set_active(state);\n  }\n  if (rofi_view_get_active() == NULL) {\n    g_main_loop_quit(main_loop);\n  }\n}\nvoid process_result(RofiViewState *state) {\n  Mode *sw = state->sw;\n  //   rofi_view_set_active ( NULL );\n  if (sw != NULL) {\n    unsigned int selected_line = rofi_view_get_selected_line(state);\n    ;\n    MenuReturn mretv = rofi_view_get_return_value(state);\n    char *input = g_strdup(rofi_view_get_user_input(state));\n    ModeMode retv = mode_result(sw, mretv, &input, selected_line);\n    {\n      if (state->text) {\n        if (input == NULL) {\n          textbox_text(state->text, \"\");\n        } else if (strcmp(rofi_view_get_user_input(state), input) != 0) {\n          textbox_text(state->text, input);\n          textbox_cursor_end(state->text);\n        }\n      }\n    }\n    g_free(input);\n\n    ModeMode mode = curr_mode;\n    // Find next enabled\n    if (retv == NEXT_DIALOG) {\n      mode = (mode + 1) % num_modes;\n    } else if (retv == PREVIOUS_DIALOG) {\n      if (mode == 0) {\n        mode = num_modes - 1;\n      } else {\n        mode = (mode - 1) % num_modes;\n      }\n    } else if (retv == RELOAD_DIALOG) {\n      // do nothing.\n    } else if (retv == RESET_DIALOG) {\n      rofi_view_clear_input(state);\n    } else if (retv < MODE_EXIT) {\n      mode = (retv) % num_modes;\n    } else {\n      mode = retv;\n    }\n    if (mode != MODE_EXIT) {\n      /**\n       * Load in the new mode.\n       */\n      rofi_view_switch_mode(state, modes[mode]);\n      curr_mode = mode;\n      return;\n    }\n    // On exit, free current view, and pop to one above.\n    rofi_view_remove_active(state);\n    rofi_view_free(state);\n    return;\n  }\n  //    rofi_view_set_active ( NULL );\n  rofi_view_remove_active(state);\n  rofi_view_free(state);\n}\n\n/**\n * Help function.\n */\nstatic void print_list_of_modes(int is_term) {\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    gboolean active = FALSE;\n    for (unsigned int j = 0; j < num_modes; j++) {\n      if (modes[j] == available_modes[i]) {\n        active = TRUE;\n        break;\n      }\n    }\n    printf(\"        • %s%s%s%s\", active ? \"+\" : \"\",\n           is_term ? (active ? color_green : color_red) : \"\",\n           mode_get_name(available_modes[i]), is_term ? color_reset : \"\");\n    if (mode_plugin_get_module(available_modes[i]) != NULL) {\n      printf(\" (external)\");\n    }\n    printf(\"\\n\");\n  }\n}\nstatic void print_main_application_options(int is_term) {\n  print_help_msg(\"-config\", \"[file]\", \"Load an alternative configuration.\",\n                 NULL, is_term);\n  print_help_msg(\"-no-config\", \"\",\n                 \"Do not load configuration, use default values.\", NULL,\n                 is_term);\n  print_help_msg(\"-v,-version\", \"\", \"Print the version number and exit.\", NULL,\n                 is_term);\n  print_help_msg(\"-dmenu\", \"\", \"Start in dmenu mode.\", NULL, is_term);\n  print_help_msg(\"-display\", \"[string]\", \"X server to contact.\", \"${DISPLAY}\",\n                 is_term);\n  print_help_msg(\"-h,-help\", \"\", \"This help message.\", NULL, is_term);\n  print_help_msg(\"-e\", \"[string]\",\n                 \"Show a dialog displaying the passed message and exit.\", NULL,\n                 is_term);\n  print_help_msg(\"-markup\", \"\", \"Enable pango markup where possible.\", NULL,\n                 is_term);\n  print_help_msg(\"-normal-window\", \"\",\n                 \"Behave as a normal window. (experimental)\", NULL, is_term);\n  print_help_msg(\"-transient-window\", \"\",\n                 \"Behave as a modal dialog that is transient to the currently \"\n                 \"focused window. (experimental)\",\n                 NULL, is_term);\n  print_help_msg(\"-show\", \"[mode]\",\n                 \"Show the mode 'mode' and exit. The mode has to be enabled.\",\n                 NULL, is_term);\n  print_help_msg(\"-no-lazy-grab\", \"\",\n                 \"Disable lazy grab that, when fail to grab keyboard, does not \"\n                 \"block but retry later.\",\n                 NULL, is_term);\n  print_help_msg(\"-no-plugins\", \"\", \"Disable loading of external plugins.\",\n                 NULL, is_term);\n  print_help_msg(\"-plugin-path\", \"\",\n                 \"Directory used to search for rofi plugins. *DEPRECATED*\",\n                 NULL, is_term);\n  print_help_msg(\"-dump-config\", \"\",\n                 \"Dump the current configuration in rasi format and exit.\",\n                 NULL, is_term);\n  print_help_msg(\"-dump-theme\", \"\",\n                 \"Dump the current theme in rasi format and exit.\", NULL,\n                 is_term);\n  print_help_msg(\"-list-keybindings\", \"\",\n                 \"Print a list of current keybindings and exit.\", NULL,\n                 is_term);\n}\n\nstatic void print_backend_info(void) {\n  int is_term = isatty(fileno(stdout));\n  printf(\"Display backends:\\n\");\n#ifdef ENABLE_XCB\n  printf(\"\\t• xcb\");\n  if (config.backend == DISPLAY_XCB) {\n    printf(\": %sselected%s\\n\", is_term ? color_bold : \"\",\n           is_term ? color_reset : \"\");\n  } else {\n    printf(\"\\n\");\n  }\n#endif\n#ifdef ENABLE_WAYLAND\n  printf(\"\\t• wayland\");\n  if (config.backend == DISPLAY_WAYLAND) {\n    printf(\": %sselected%s\\n\", is_term ? color_bold : \"\",\n           is_term ? color_reset : \"\");\n  } else {\n    printf(\"\\n\");\n  }\n#endif\n  printf(\"\\n\");\n}\n\nstatic void help(G_GNUC_UNUSED int argc, char **argv, const gboolean compact) {\n  int is_term = isatty(fileno(stdout));\n  if (!compact) {\n    printf(\"%s usage:\\n\", argv[0]);\n    printf(\"\\t%s [-options ...]\\n\\n\", argv[0]);\n    printf(\"Command line only options:\\n\");\n    print_main_application_options(is_term);\n    printf(\"DMENU command line options:\\n\");\n    print_dmenu_options();\n    printf(\"Global options:\\n\");\n    print_options();\n    printf(\"\\n\");\n  }\n  print_backend_info();\n  if (display_setup_success) {\n#ifdef ENABLE_XCB\n    if (config.backend == DISPLAY_XCB) {\n      printf(\"Detected Window manager:\\n\");\n      char *wm = x11_helper_get_window_manager();\n      if (wm) {\n        printf(\"\\t• %s\\n\", wm);\n        g_free(wm);\n      } else {\n        printf(\"\\t• No window manager detected.\\n\");\n      }\n      printf(\"\\n\");\n    }\n#endif\n    display_dump_monitor_layout();\n    printf(\"\\n\");\n  }\n  printf(\"Detected modes:\\n\");\n  print_list_of_modes(is_term);\n  printf(\"\\n\");\n  printf(\"Detected user scripts:\\n\");\n  script_user_list(is_term);\n  printf(\"\\n\");\n  printf(\"Compile time options:\\n\");\n  printf(\"\\t• Pango   version %s\\n\", pango_version_string());\n#ifdef WINDOW_MODE\n  printf(\"\\t• window  %senabled%s\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\");\n#else\n  printf(\"\\t• window  %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n#ifdef ENABLE_DRUN\n  printf(\"\\t• drun    %senabled%s\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\");\n#else\n  printf(\"\\t• drun    %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n#ifdef ENABLE_ASAN\n  printf(\"\\t• asan    %senabled%s\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\");\n#else\n  printf(\"\\t• asan    %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n#ifdef XCB_IMDKIT\n  printf(\"\\t• imdkit  %senabled%s\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\");\n#else\n  printf(\"\\t• imdkit  %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n#ifdef ENABLE_XCB\n  printf(\"\\t• xcb     %senabled%s\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\");\n#else\n  printf(\"\\t• xcb     %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n#ifdef ENABLE_WAYLAND\n  printf(\"\\t• wayland %senabled%s (%s)\\n\", is_term ? color_green : \"\",\n         is_term ? color_reset : \"\", WAYLAND_VERSION);\n#else\n  printf(\"\\t• wayland %sdisabled%s\\n\", is_term ? color_red : \"\",\n         is_term ? color_reset : \"\");\n#endif\n  printf(\"\\n\");\n  printf(\"For more information see: %sman rofi%s\\n\", is_term ? color_bold : \"\",\n         is_term ? color_reset : \"\");\n#ifdef GIT_VERSION\n  printf(\"                 Version: %s\" GIT_VERSION \"%s\\n\",\n         is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n#else\n  printf(\"                 Version: %s\" VERSION \"%s\\n\",\n         is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n#endif\n  printf(\"              Bugreports: %s\" PACKAGE_BUGREPORT \"%s\\n\",\n         is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n  printf(\"                 Support: %s\" PACKAGE_URL \"%s\\n\",\n         is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n  printf(\"                          %s#rofi @ libera.chat%s\\n\",\n         is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n  if (find_arg(\"-no-config\") < 0) {\n    if (config_path) {\n      printf(\"      Configuration file: %s%s%s\\n\", is_term ? color_bold : \"\",\n             config_path, is_term ? color_reset : \"\");\n    }\n  } else {\n    printf(\"      Configuration file: %sDisabled%s\\n\",\n           is_term ? color_bold : \"\", is_term ? color_reset : \"\");\n  }\n  rofi_theme_print_parsed_files(is_term);\n}\n\nstatic void help_print_disabled_mode(const char *mode) {\n  int is_term = isatty(fileno(stdout));\n  // Only  output to terminal\n  if (is_term) {\n    fprintf(stderr, \"Mode %s%s%s is not enabled. I have enabled it for now.\\n\",\n            color_red, mode, color_reset);\n    fprintf(stderr,\n            \"Please consider adding %s%s%s to the list of enabled modes: \"\n            \"%smodes: [%s%s%s,%s]%s.\\n\",\n            color_red, mode, color_reset, color_green, config.modes,\n            color_reset, color_red, mode, color_reset);\n  }\n}\nstatic void help_print_mode_not_found(const char *mode) {\n  GString *str = g_string_new(\"\");\n  g_string_printf(\n      str, \"Mode %s is not found.\\nThe following modes are known:\\n\", mode);\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    gboolean active = FALSE;\n    for (unsigned int j = 0; j < num_modes; j++) {\n      if (modes[j] == available_modes[i]) {\n        active = TRUE;\n        break;\n      }\n    }\n    g_string_append_printf(str, \"        * %s%s\\n\", active ? \"+\" : \"\",\n                           mode_get_name(available_modes[i]));\n  }\n  rofi_add_error_message(str);\n}\nstatic void help_print_no_arguments(void) {\n\n  GString *emesg = g_string_new(\n      \"<span size=\\\"x-large\\\">Rofi is unsure what to show.</span>\\n\\n\");\n  g_string_append(emesg, \"Please specify the mode you want to show.\\n\\n\");\n  g_string_append(\n      emesg, \"    <b>rofi</b> -show <span color=\\\"green\\\">{mode}</span>\\n\\n\");\n  g_string_append(emesg, \"The following modes are enabled:\\n\");\n  for (unsigned int j = 0; j < num_modes; j++) {\n    g_string_append_printf(emesg, \"    • <span color=\\\"green\\\">%s</span>\\n\",\n                           mode_get_name(modes[j]));\n  }\n  g_string_append(emesg, \"\\nThe following modes can be enabled:\\n\");\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    gboolean active = FALSE;\n    for (unsigned int j = 0; j < num_modes; j++) {\n      if (modes[j] == available_modes[i]) {\n        active = TRUE;\n        break;\n      }\n    }\n    if (!active) {\n      g_string_append_printf(emesg, \"    • <span color=\\\"red\\\">%s</span>\\n\",\n                             mode_get_name(available_modes[i]));\n    }\n  }\n  g_string_append(emesg, \"\\nTo activate a mode, add it to the list in \"\n                         \"the <span color=\\\"green\\\">modes</span> \"\n                         \"setting.\\n\");\n  rofi_view_error_dialog(emesg->str, ERROR_MSG_MARKUP);\n  rofi_set_return_code(EXIT_SUCCESS);\n}\n\n/**\n * Cleanup globally allocated memory.\n */\nstatic void cleanup(void) {\n  for (unsigned int i = 0; i < num_modes; i++) {\n    mode_destroy(modes[i]);\n  }\n  rofi_view_workers_finalize();\n  if (main_loop != NULL) {\n    g_main_loop_unref(main_loop);\n    main_loop = NULL;\n  }\n  // Cleanup\n  display_cleanup();\n\n  nk_bindings_free(bindings);\n\n  // Cleaning up memory allocated by the Xresources file.\n  config_xresource_free();\n  g_free(modes);\n\n  g_free(config_path);\n\n  rofi_clear_error_messages();\n  rofi_clear_warning_messages();\n\n  if (rofi_theme) {\n    rofi_theme_free(rofi_theme);\n    rofi_theme = NULL;\n  }\n  TIMINGS_STOP();\n  script_mode_cleanup();\n  rofi_collectmodes_destroy();\n  rofi_icon_fetcher_destroy();\n\n  rofi_theme_free_parsed_files();\n  if (rofi_configuration) {\n    rofi_theme_free(rofi_configuration);\n    rofi_configuration = NULL;\n  }\n  // Cleanup memory allocated by rofi_expand_path\n  if (cache_dir_alloc) {\n    g_free(cache_dir_alloc);\n    cache_dir_alloc = NULL;\n  }\n}\n\n/**\n * Collected modes\n */\n\nMode *rofi_collect_modes_search(const char *name) {\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    if (g_strcmp0(name, mode_get_name(available_modes[i])) == 0) {\n      return available_modes[i];\n    }\n  }\n  return NULL;\n}\n/**\n * @param mode Add mode to list.\n *\n * @returns TRUE when success.\n */\nstatic gboolean rofi_collectmodes_add(Mode *mode) {\n  Mode *m = rofi_collect_modes_search(mode_get_name(mode));\n  if (m == NULL) {\n    available_modes =\n        g_realloc(available_modes, sizeof(Mode *) * (num_available_modes + 1));\n    // Set mode.\n    available_modes[num_available_modes] = mode;\n    num_available_modes++;\n    return TRUE;\n  }\n  return FALSE;\n}\n\nstatic void rofi_collectmodes_dir(const char *base_dir) {\n  g_debug(\"Looking into: %s for plugins\", base_dir);\n  GDir *dir = g_dir_open(base_dir, 0, NULL);\n  if (dir) {\n    const char *dn = NULL;\n    while ((dn = g_dir_read_name(dir))) {\n      if (!g_str_has_suffix(dn, G_MODULE_SUFFIX)) {\n        continue;\n      }\n      char *fn = g_build_filename(base_dir, dn, NULL);\n      g_debug(\"Trying to open: %s plugin\", fn);\n      GModule *mod =\n          g_module_open(fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);\n      if (mod) {\n        Mode *m = NULL;\n        if (g_module_symbol(mod, \"mode\", (gpointer *)&m)) {\n          if (mode_get_abi_version(m) != ABI_VERSION) {\n            g_warning(\"ABI version of plugin: '%s' does not match: %08X \"\n                      \"expecting: %08X\",\n                      dn, mode_get_abi_version(m), ABI_VERSION);\n            g_module_close(mod);\n          } else {\n            mode_plugin_set_module(m, mod);\n            if (!rofi_collectmodes_add(m)) {\n              g_module_close(mod);\n            }\n          }\n        } else {\n          g_warning(\"Symbol 'mode' not found in module: %s\", dn);\n          g_module_close(mod);\n        }\n      } else {\n        g_warning(\"Failed to open 'mode' plugin: '%s', error: %s\", dn,\n                  g_module_error());\n      }\n      g_free(fn);\n    }\n    g_dir_close(dir);\n  }\n}\n\n/**\n * Find all available modes.\n */\nstatic void rofi_collect_modes(void) {\n#ifdef WINDOW_MODE\n#ifdef ENABLE_XCB\n  if (config.backend == DISPLAY_XCB) {\n    rofi_collectmodes_add(&window_mode);\n    rofi_collectmodes_add(&window_mode_cd);\n  }\n#endif\n#ifdef ENABLE_WAYLAND\n  if (config.backend == DISPLAY_WAYLAND) {\n    rofi_collectmodes_add(&wayland_window_mode);\n  }\n#endif\n#endif // WINDOW_MODE\n  rofi_collectmodes_add(&run_mode);\n  rofi_collectmodes_add(&ssh_mode);\n#ifdef ENABLE_DRUN\n  rofi_collectmodes_add(&drun_mode);\n#endif\n  rofi_collectmodes_add(&combi_mode);\n  rofi_collectmodes_add(&help_keys_mode);\n  rofi_collectmodes_add(&file_browser_mode);\n  rofi_collectmodes_add(&recursive_browser_mode);\n\n  if (find_arg(\"-no-plugins\") < 0) {\n    find_arg_str(\"-plugin-path\", &(config.plugin_path));\n    g_debug(\"Parse plugin path: %s\", config.plugin_path);\n    rofi_collectmodes_dir(config.plugin_path);\n    /* ROFI_PLUGIN_PATH */\n    const char *path = g_getenv(\"ROFI_PLUGIN_PATH\");\n    if (path != NULL) {\n      gchar **paths = g_strsplit(path, \":\", -1);\n      for (unsigned int i = 0; paths[i]; i++) {\n        rofi_collectmodes_dir(paths[i]);\n      }\n      g_strfreev(paths);\n    }\n  }\n  script_mode_gather_user_scripts();\n}\n\n/**\n * Setup configuration for config.\n */\nstatic void rofi_collectmodes_setup(void) {\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    mode_set_config(available_modes[i]);\n  }\n}\nstatic void rofi_collectmodes_destroy(void) {\n  for (unsigned int i = 0; i < num_available_modes; i++) {\n    if (mode_plugin_get_module(available_modes[i])) {\n      GModule *mod = mode_plugin_get_module(available_modes[i]);\n      available_modes[i] = NULL;\n      g_module_close(mod);\n    }\n    if (available_modes[i]) {\n      mode_free(&(available_modes[i]));\n    }\n  }\n  g_free(available_modes);\n  available_modes = NULL;\n  num_available_modes = 0;\n}\n\n/**\n * Parse the mode string, into internal array of type Mode.\n *\n * String is split on separator ','\n * First the three build-in modes are checked: window, run, ssh\n * if that fails, a script-mode is created.\n */\nstatic int add_mode(const char *token) {\n  unsigned int index = num_modes;\n  // Resize and add entry.\n  modes = (Mode **)g_realloc(modes, sizeof(Mode *) * (num_modes + 1));\n\n  Mode *mode = rofi_collect_modes_search(token);\n  if (mode) {\n    modes[num_modes] = mode;\n    num_modes++;\n  } else if (script_mode_is_valid(token)) {\n    // If not build in, use custom mode.\n    Mode *sw = script_mode_parse_setup(token);\n    if (sw != NULL) {\n      // Add to available list, so combi can find it.\n      rofi_collectmodes_add(sw);\n      mode_set_config(sw);\n      modes[num_modes] = sw;\n      num_modes++;\n    }\n  }\n  return (index == num_modes) ? -1 : (int)index;\n}\nstatic gboolean setup_modes(void) {\n  const char *const sep = \",#\";\n  char *savept = NULL;\n  // Make a copy, as strtok will modify it.\n  char *mode_str = g_strdup(config.modes);\n  // Split token on ','. This modifies mode_str.\n  for (char *token = strtok_r(mode_str, sep, &savept); token != NULL;\n       token = strtok_r(NULL, sep, &savept)) {\n    if (add_mode(token) == -1) {\n      help_print_mode_not_found(token);\n    }\n  }\n  // Free string that was modified by strtok_r\n  g_free(mode_str);\n  return FALSE;\n}\n\n/**\n * Quit rofi mainloop.\n * This will exit program.\n **/\nvoid rofi_quit_main_loop(void) { g_main_loop_quit(main_loop); }\n\nstatic gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data) {\n  // Break out of loop.\n  g_main_loop_quit(main_loop);\n  return G_SOURCE_CONTINUE;\n}\nstatic void show_error_dialog(void) {\n  GString *emesg =\n      g_string_new(\"The following errors were detected when starting rofi:\\n\");\n  GList *iter = g_list_first(list_of_error_msgs);\n  int index = 0;\n  for (; iter != NULL && index < 2; iter = g_list_next(iter)) {\n    GString *msg = (GString *)(iter->data);\n    g_string_append(emesg, \"\\n\\n\");\n    g_string_append(emesg, msg->str);\n    index++;\n  }\n  if (g_list_length(iter) > 1) {\n    g_string_append_printf(emesg, \"\\nThere are <b>%u</b> more errors.\",\n                           g_list_length(iter) - 1);\n  }\n  rofi_view_error_dialog(emesg->str, ERROR_MSG_MARKUP);\n  g_string_free(emesg, TRUE);\n  rofi_set_return_code(EX_DATAERR);\n}\n\nstatic gboolean startup(G_GNUC_UNUSED gpointer data) {\n  TICK_N(\"Startup\");\n  // flags to run immediately and exit\n  char *sname = NULL;\n  char *msg = NULL;\n  MenuFlags window_flags = MENU_NORMAL;\n\n  if (find_arg(\"-normal-window\") >= 0) {\n    window_flags |= MENU_NORMAL_WINDOW;\n  }\n  if (find_arg(\"-transient-window\") >= 0) {\n    window_flags |= MENU_TRANSIENT_WINDOW;\n  }\n  TICK_N(\"Grab keyboard\");\n  __create_window(window_flags);\n  TICK_N(\"Create Window\");\n  // Parse the keybindings.\n  TICK_N(\"Parse ABE\");\n  // Sanity check\n  config_sanity_check();\n  TICK_N(\"Config sanity check\");\n\n  if (list_of_error_msgs != NULL) {\n    show_error_dialog();\n    return G_SOURCE_REMOVE;\n  }\n  if (list_of_warning_msgs != NULL) {\n    for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;\n         iter = g_list_next(iter)) {\n      fputs(((GString *)iter->data)->str, stderr);\n      fputs(\"\\n\", stderr);\n    }\n  }\n  // Dmenu mode.\n  if (rofi_is_in_dmenu_mode == TRUE) {\n    // force off sidebar mode:\n    config.sidebar_mode = FALSE;\n    int retv = dmenu_mode_dialog();\n    if (retv) {\n      rofi_set_return_code(EXIT_SUCCESS);\n      // Directly exit.\n      g_main_loop_quit(main_loop);\n    }\n  } else if (find_arg_str(\"-e\", &(msg))) {\n    int markup = FALSE;\n    if (find_arg(\"-markup\") >= 0) {\n      markup = TRUE;\n    }\n    // When we pass -, we read from stdin.\n    if (g_strcmp0(msg, \"-\") == 0) {\n      size_t index = 0, i = 0;\n      size_t length = 1024;\n      msg = malloc(length * sizeof(char));\n      while ((i = fread(&msg[index], 1, 1024, stdin)) > 0) {\n        index += i;\n        length += i;\n        if (length >= ROFI_MAX_DMENU_INPUT) {\n          break;\n        }\n        msg = realloc(msg, length * sizeof(char));\n      }\n\n      msg[index] = 0;\n\n      if (!rofi_view_error_dialog(msg, markup)) {\n        g_main_loop_quit(main_loop);\n      }\n      g_free(msg);\n    } else {\n      // Normal version\n      if (!rofi_view_error_dialog(msg, markup)) {\n        g_main_loop_quit(main_loop);\n      }\n    }\n  } else if (find_arg_str(\"-show\", &sname) == TRUE) {\n    int index = mode_lookup(sname);\n    if (index < 0) {\n      // Add it to the list\n      index = add_mode(sname);\n      // Complain\n      if (index >= 0) {\n        help_print_disabled_mode(sname);\n      }\n      // Run it anyway if found.\n    }\n    if (index >= 0) {\n      run_mode_index(index);\n    } else {\n      help_print_mode_not_found(sname);\n      show_error_dialog();\n      return G_SOURCE_REMOVE;\n    }\n  } else if (find_arg(\"-show\") >= 0 && num_modes > 0) {\n    run_mode_index(0);\n  } else {\n    help_print_no_arguments();\n\n    // g_main_loop_quit(main_loop);\n  }\n\n  return G_SOURCE_REMOVE;\n}\n\nstatic gboolean take_screenshot_quit(G_GNUC_UNUSED void *data) {\n  rofi_capture_screenshot();\n  rofi_quit_main_loop();\n  return G_SOURCE_REMOVE;\n}\nstatic gboolean record(G_GNUC_UNUSED void *data) {\n  rofi_capture_screenshot();\n  return G_SOURCE_CONTINUE;\n}\nstatic void rofi_custom_log_function(const char *log_domain,\n                                     G_GNUC_UNUSED GLogLevelFlags log_level,\n                                     const gchar *message, gpointer user_data) {\n  int fp = GPOINTER_TO_INT(user_data);\n  dprintf(fp, \"[%s]: %s\\n\", log_domain == NULL ? \"default\" : log_domain,\n          message);\n}\n/**\n * @param argc number of input arguments.\n * @param argv array of the input arguments.\n *\n * Main application entry point.\n *\n * @returns return code of rofi.\n */\nint main(int argc, char *argv[]) {\n  cmd_set_arguments(argc, argv);\n  if (find_arg(\"-log\") >= 0) {\n    char *logfile = NULL;\n    find_arg_str(\"-log\", &logfile);\n    if (logfile != NULL) {\n      int fp = open(logfile, O_CLOEXEC | O_APPEND | O_CREAT | O_WRONLY,\n                    S_IRUSR | S_IWUSR);\n      if (fp != -1) {\n        g_log_set_default_handler(rofi_custom_log_function,\n                                  GINT_TO_POINTER(fp));\n\n      } else {\n        g_error(\"Failed to open logfile '%s': %s.\", logfile, strerror(errno));\n      }\n\n    } else {\n      g_warning(\"Option '-log' should pass in a filename.\");\n    }\n  }\n  TIMINGS_START();\n\n  // Version\n  if (find_arg(\"-v\") >= 0 || find_arg(\"-version\") >= 0) {\n#ifdef GIT_VERSION\n    g_print(\"Version: \" GIT_VERSION \"\\n\");\n#else\n    g_print(\"Version: \" VERSION \"\\n\");\n#endif\n    return EXIT_SUCCESS;\n  }\n\n  if (find_arg(\"-rasi-validate\") >= 0) {\n    char *str = NULL;\n    find_arg_str(\"-rasi-validate\", &str);\n    if (str != NULL) {\n      int retv = rofi_theme_rasi_validate(str);\n      cleanup();\n      return retv;\n    }\n    fprintf(stderr, \"Usage: %s -rasi-validate my-theme.rasi\", argv[0]);\n    return EXIT_FAILURE;\n  }\n\n  {\n    const char *ro_pid = g_getenv(\"ROFI_OUTSIDE\");\n    if (ro_pid != NULL) {\n      pid_t ro_pidi = (pid_t)g_ascii_strtoll(ro_pid, NULL, 0);\n      if (kill(ro_pidi, 0) == 0) {\n        printf(\"Do not launch rofi from inside rofi.\\r\\n\");\n        return EXIT_FAILURE;\n      }\n    }\n  }\n\n  // Detect if we are in dmenu mode.\n  // This has two possible causes.\n  // 1 the user specifies it on the command-line.\n  if (find_arg(\"-dmenu\") >= 0) {\n    rofi_is_in_dmenu_mode = TRUE;\n  }\n  // 2 the binary that executed is called dmenu (e.g. symlink to rofi)\n  else {\n    // Get the base name of the executable called.\n    char *base_name = g_path_get_basename(argv[0]);\n    const char *const dmenu_str = \"dmenu\";\n    rofi_is_in_dmenu_mode = (strcmp(base_name, dmenu_str) == 0);\n    // Free the basename for dmenu detection.\n    g_free(base_name);\n  }\n  TICK();\n\n  // Create pid file path.\n  const char *path = g_get_user_runtime_dir();\n  if (path) {\n    if (g_mkdir_with_parents(path, 0700) < 0) {\n      g_warning(\"Failed to create user runtime directory: %s with error: %s\",\n                path, g_strerror(errno));\n      pidfile = g_build_filename(g_get_home_dir(), \".rofi.pid\", NULL);\n    } else {\n      pidfile = g_build_filename(path, \"rofi.pid\", NULL);\n    }\n  }\n  config_parser_add_option(xrm_String, \"pid\", (void **)&pidfile,\n                           \"Pidfile location\");\n\n  /** default configuration */\n  if (find_arg(\"-no-default-config\") < 0) {\n    GBytes *theme_data = g_resource_lookup_data(\n        resources_get_resource(), \"/org/qtools/rofi/default_configuration.rasi\",\n        G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);\n    if (theme_data) {\n      const char *theme = g_bytes_get_data(theme_data, NULL);\n      if (rofi_theme_parse_string((const char *)theme)) {\n        g_warning(\"Failed to parse default configuration. Giving up..\");\n        if (list_of_error_msgs) {\n          for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;\n               iter = g_list_next(iter)) {\n            g_warning(\"Error: %s%s%s\", color_bold, ((GString *)iter->data)->str,\n                      color_reset);\n          }\n        }\n        rofi_configuration = NULL;\n        cleanup();\n        return EXIT_FAILURE;\n      }\n      g_bytes_unref(theme_data);\n    }\n  }\n\n  if (find_arg(\"-config\") < 0) {\n    const char *cpath = g_get_user_config_dir();\n    if (cpath) {\n      config_path = g_build_filename(cpath, \"rofi\", \"config.rasi\", NULL);\n    }\n  } else {\n    char *c = NULL;\n    find_arg_str(\"-config\", &c);\n    config_path = rofi_expand_path(c);\n  }\n  TICK();\n\n  const struct _display_proxy *proxy = NULL;\n#ifdef ENABLE_XCB\n  proxy = xcb_proxy;\n  config.backend = DISPLAY_XCB;\n#endif\n\n#ifdef ENABLE_WAYLAND\n#ifdef ENABLE_XCB\n  const gchar *wl_display = g_getenv(\"WAYLAND_DISPLAY\");\n  if (find_arg(\"-x11\") < 0 && find_arg(\"-xcb\") < 0 && wl_display != NULL &&\n      strlen(wl_display) > 0) {\n    proxy = wayland_proxy;\n    config.backend = DISPLAY_WAYLAND;\n  }\n#else\n  proxy = wayland_proxy;\n  config.backend = DISPLAY_WAYLAND;\n#endif\n#endif\n\n  display_init(proxy);\n\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    g_warning(\"Failed to set locale.\");\n    cleanup();\n    return EXIT_FAILURE;\n  }\n\n  TICK_N(\"Setup Locale\");\n  rofi_collect_modes();\n  TICK_N(\"Collect MODES\");\n  rofi_collectmodes_setup();\n  TICK_N(\"Setup MODES\");\n\n  main_loop = g_main_loop_new(NULL, FALSE);\n\n  TICK_N(\"Setup mainloop\");\n\n  bindings = nk_bindings_new(0lu);\n  TICK_N(\"NK Bindings\");\n\n  // Setup keybinding\n  setup_abe();\n  TICK_N(\"Setup abe\");\n\n  if (find_arg(\"-no-config\") < 0) {\n    // Load distro default settings\n    gboolean found_system = FALSE;\n    const char *const *dirs = g_get_system_config_dirs();\n    if (dirs) {\n      for (unsigned int i = 0; !found_system && dirs[i]; i++) {\n        /** New format. */\n        gchar *etc = g_build_filename(dirs[i], \"rofi.rasi\", NULL);\n        g_debug(\"Look for default config file: %s\", etc);\n        if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {\n          g_debug(\"Parsing: %s\", etc);\n          rofi_theme_parse_file(etc);\n          found_system = TRUE;\n        }\n        g_free(etc);\n      }\n    }\n    if (!found_system) {\n      /** New format. */\n      gchar *etc = g_build_filename(SYSCONFDIR, \"rofi.rasi\", NULL);\n      g_debug(\"Look for default config file: %s\", etc);\n      if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {\n        g_debug(\"Look for default config file: %s\", etc);\n        rofi_theme_parse_file(etc);\n      }\n      g_free(etc);\n    }\n\n    if (config_path) {\n      // Try to resolve the path.\n      extern const char *rasi_theme_file_extensions[];\n      char *file2 =\n          helper_get_theme_path(config_path, rasi_theme_file_extensions, NULL);\n      GFile *gf = g_file_new_for_path(file2);\n      char *filename = g_file_get_path(gf);\n      g_object_unref(gf);\n      g_free(file2);\n      if (filename && g_file_test(filename, G_FILE_TEST_EXISTS)) {\n        if (rofi_theme_parse_file(filename)) {\n          rofi_theme_free(rofi_theme);\n          rofi_theme = NULL;\n        }\n      }\n      g_free(filename);\n    }\n  }\n  find_arg_str(\"-theme\", &(config.theme));\n  if (config.theme) {\n    TICK_N(\"Parse theme\");\n    rofi_theme_reset();\n    if (rofi_theme_parse_file(config.theme)) {\n      g_warning(\"Failed to parse theme: \\\"%s\\\"\", config.theme);\n      // TODO: instantiate fallback theme.?\n      rofi_theme_free(rofi_theme);\n      rofi_theme = NULL;\n    }\n    TICK_N(\"Parsed theme\");\n  }\n  // Parse command line for settings, independent of other -no-config.\n  if (list_of_error_msgs == NULL) {\n    // Only call this when there are no errors.\n    // This might clear existing errors.\n    config_parse_cmd_options();\n  }\n\n  if (rofi_theme == NULL || rofi_theme->num_widgets == 0) {\n    g_debug(\"Failed to load theme. Try to load default: \");\n    rofi_theme_parse_string(\"@theme \\\"default\\\"\");\n  }\n  TICK_N(\"Load cmd config \");\n\n  // Get the path to the cache dir.\n  cache_dir = g_get_user_cache_dir();\n\n  if (config.cache_dir != NULL) {\n    cache_dir = cache_dir_alloc = rofi_expand_path(config.cache_dir);\n  }\n\n  if (g_mkdir_with_parents(cache_dir, 0700) < 0) {\n    g_warning(\"Failed to create cache directory: %s\", g_strerror(errno));\n    return EXIT_FAILURE;\n  }\n\n  /** dirty hack for dmenu compatibility */\n  char *windowid = NULL;\n  if (!rofi_is_in_dmenu_mode) {\n    // setup_modes\n    if (setup_modes()) {\n      cleanup();\n      return EXIT_FAILURE;\n    }\n    TICK_N(\"Setup Modes\");\n  } else {\n    // Hack for dmenu compatibility.\n    if (find_arg_str(\"-w\", &windowid) == TRUE) {\n      config.monitor = g_strdup_printf(\"wid:%s\", windowid);\n      windowid = config.monitor;\n    }\n  }\n\n  /**\n   * Make small commandline changes to the current theme.\n   */\n  const char **theme_str = find_arg_strv(\"-theme-str\");\n  if (theme_str) {\n    for (int index = 0; theme_str[index]; index++) {\n      if (rofi_theme_parse_string(theme_str[index])) {\n        g_warning(\"Failed to parse -theme-str option: \\\"%s\\\"\",\n                  theme_str[index]);\n        rofi_theme_free(rofi_theme);\n        rofi_theme = NULL;\n      }\n    }\n    g_free(theme_str);\n  }\n\n  parse_keys_abe(bindings);\n  if (find_arg(\"-dump-theme\") >= 0) {\n    rofi_theme_print(rofi_theme);\n    cleanup();\n    return EXIT_SUCCESS;\n  }\n  if (find_arg(\"-dump-processed-theme\") >= 0) {\n    rofi_theme_parse_process_conditionals();\n    rofi_theme_print(rofi_theme);\n    cleanup();\n    return EXIT_SUCCESS;\n  }\n  if (find_arg(\"-dump-config\") >= 0) {\n    config_parse_dump_config_rasi_format(stdout, FALSE);\n    cleanup();\n    return EXIT_SUCCESS;\n  }\n\n  if (find_arg(\"-list-keybindings\") >= 0) {\n    int is_term = isatty(fileno(stdout));\n    abe_list_all_bindings(is_term);\n    return EXIT_SUCCESS;\n  }\n\n  unsigned int interval = 1;\n  if (find_arg_uint(\"-record-screenshots\", &interval)) {\n    g_timeout_add((guint)(1000 / (double)interval), record, NULL);\n  }\n  if (find_arg_uint(\"-take-screenshot-quit\", &interval)) {\n    g_timeout_add(interval, take_screenshot_quit, NULL);\n  }\n  if (find_arg(\"-benchmark-ui\") >= 0) {\n    config.benchmark_ui = TRUE;\n  }\n\n  display_setup_success = display_setup(main_loop, bindings);\n  TICK_N(\"Setup Display\");\n\n  // catch help request\n  if (find_arg(\"-h\") >= 0 || find_arg(\"-help\") >= 0 ||\n      find_arg(\"--help\") >= 0) {\n    help(argc, argv, FALSE);\n    cleanup();\n    return EXIT_SUCCESS;\n  }\n  if (find_arg(\"-info\") >= 0 || find_arg(\"--info\") >= 0) {\n    help(argc, argv, TRUE);\n    cleanup();\n    return EXIT_SUCCESS;\n  }\n\n  if (!display_setup_success) {\n#ifdef ENABLE_WAYLAND\n#ifdef ENABLE_XCB\n    g_warning(\"No valid backend was found. Make sure to launch %s from a valid \"\n              \"X11 or Wayland session.\",\n              argv[0]);\n#else\n    g_warning(\"No valid backend was found. Make sure to launch %s from a valid \"\n              \"Wayland session.\",\n              argv[0]);\n\n#endif\n#else\n    g_warning(\"No valid backend was found. Make sure to launch %s from a valid \"\n              \"X11 session.\",\n              argv[0]);\n#endif\n    cleanup();\n    return EXIT_FAILURE;\n  }\n\n  rofi_view_workers_initialize();\n  TICK_N(\"Workers initialize\");\n  rofi_icon_fetcher_init();\n  TICK_N(\"Icon fetcher initialize\");\n\n  gboolean kill_running = FALSE;\n  if (find_arg(\"-replace\") >= 0) {\n    kill_running = TRUE;\n  }\n  // Create pid file\n  int pfd = create_pid_file(pidfile, kill_running);\n  TICK_N(\"Pid file created\");\n  if (pfd < 0) {\n    cleanup();\n    return EXIT_FAILURE;\n  }\n  textbox_setup();\n  TICK_N(\"Text box setup\");\n\n  if (!display_late_setup()) {\n    g_warning(\"Failed to properly finish display setup\");\n    cleanup();\n    return EXIT_FAILURE;\n  }\n  TICK_N(\"Setup late Display\");\n\n  rofi_theme_set_disp_scale_func(display_scale);\n  rofi_theme_parse_process_conditionals();\n  rofi_theme_parse_process_links();\n  TICK_N(\"Theme setup\");\n\n  // Setup signal handling sources.\n  // SIGINT\n  g_unix_signal_add(SIGINT, main_loop_signal_handler_int, NULL);\n\n  g_idle_add(startup, NULL);\n\n  // Start mainloop.\n  g_main_loop_run(main_loop);\n  teardown(pfd);\n  cleanup();\n\n  /* dirty hack */\n  g_free(windowid);\n  return return_code;\n}\n\n/** List of error messages.*/\nextern GList *list_of_error_msgs;\nint rofi_theme_rasi_validate(const char *filename) {\n  rofi_theme_parse_file(filename);\n  rofi_theme_parse_process_links();\n  if (list_of_error_msgs == NULL && list_of_warning_msgs == NULL) {\n    return EXIT_SUCCESS;\n  }\n\n  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;\n       iter = g_list_next(iter)) {\n    fputs(((GString *)iter->data)->str, stderr);\n    fputs(\"\\n\", stderr);\n  }\n  for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;\n       iter = g_list_next(iter)) {\n    fputs(((GString *)iter->data)->str, stderr);\n    fputs(\"\\n\", stderr);\n  }\n\n  return EXIT_FAILURE;\n}\n\nconst Mode *rofi_get_completer(void) {\n  const Mode *index = mode_available_lookup(config.completer_mode);\n  if (index != NULL) {\n    return index;\n  }\n  const char *name =\n      config.completer_mode == NULL ? \"(null)\" : config.completer_mode;\n  g_warning(\"Mode: %s not found or is not valid for use as completer.\", name);\n  return NULL;\n}\n"
  },
  {
    "path": "source/theme.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** Log domain used by the theme engine.*/\n#define G_LOG_DOMAIN \"Theme\"\n\n#include \"config.h\"\n#include <math.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n// GFile stuff.\n#include \"display.h\"\n#include \"helper.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi-types.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"theme-parser.h\"\n#include \"theme.h\"\n#include \"view.h\"\n#include \"widgets/textbox.h\"\n#include <gio/gio.h>\n\n/**\n * list of config files we parsed.\n */\nGList *parsed_config_files = NULL;\nstatic disp_scale_func disp_scale = NULL;\n\n/** cleanup (free) the list of parsed config files. */\nvoid rofi_theme_free_parsed_files(void) {\n  g_list_free_full(parsed_config_files, g_free);\n  parsed_config_files = NULL;\n}\n\n/**\n * @param is_term if print to terminal\n *\n * print the list of parsed config files.\n */\nvoid rofi_theme_print_parsed_files(gboolean is_term) {\n  printf(\"\\nParsed files:\\n\");\n  for (GList *iter = g_list_first(parsed_config_files); iter != NULL;\n       iter = g_list_next(iter)) {\n    printf(\"\\t\\u2023 %s%s%s\\n\", is_term ? color_bold : \"\",\n           (const char *)(iter->data), is_term ? color_reset : \"\");\n  }\n  printf(\"\\n\");\n}\n\nvoid yyerror(YYLTYPE *yylloc, const char *, const char *);\nstatic gboolean distance_compare(RofiDistance d, RofiDistance e) {\n  // TODO UPDATE\n  return d.base.type == e.base.type && d.base.distance == e.base.distance &&\n         d.style == e.style;\n}\n\nThemeWidget *rofi_theme_find_or_create_name(ThemeWidget *base,\n                                            const char *name) {\n  for (unsigned int i = 0; i < base->num_widgets; i++) {\n    if (g_strcmp0(base->widgets[i]->name, name) == 0) {\n      return base->widgets[i];\n    }\n  }\n\n  base->widgets =\n      g_realloc(base->widgets, sizeof(ThemeWidget *) * (base->num_widgets + 1));\n  base->widgets[base->num_widgets] = g_slice_new0(ThemeWidget);\n  ThemeWidget *retv = base->widgets[base->num_widgets];\n  retv->parent = base;\n  retv->name = g_strdup(name);\n  base->num_widgets++;\n  return retv;\n}\n/**\n *  Properties\n */\nProperty *rofi_theme_property_create(PropertyType type) {\n  Property *retv = g_slice_new0(Property);\n  retv->type = type;\n  return retv;\n}\n\nstatic RofiDistanceUnit *\nrofi_theme_property_copy_distance_unit(RofiDistanceUnit *unit) {\n  RofiDistanceUnit *retv = g_slice_new0(RofiDistanceUnit);\n  *retv = *unit;\n  if (unit->left) {\n    retv->left = rofi_theme_property_copy_distance_unit(unit->left);\n  }\n  if (unit->right) {\n    retv->right = rofi_theme_property_copy_distance_unit(unit->right);\n  }\n  return retv;\n}\nRofiDistance rofi_theme_property_copy_distance(RofiDistance const distance) {\n  RofiDistance retv = distance;\n  if (distance.base.left) {\n    retv.base.left = rofi_theme_property_copy_distance_unit(distance.base.left);\n  }\n  if (distance.base.right) {\n    retv.base.right =\n        rofi_theme_property_copy_distance_unit(distance.base.right);\n  }\n  return retv;\n}\n\nProperty *rofi_theme_property_copy(const Property *p,\n                                   G_GNUC_UNUSED void *data) {\n  Property *retv = rofi_theme_property_create(p->type);\n  retv->name = g_strdup(p->name);\n\n  switch (p->type) {\n  case P_STRING:\n    retv->value.s = g_strdup(p->value.s);\n    break;\n  case P_LIST:\n    retv->value.list = g_list_copy_deep(\n        p->value.list, (GCopyFunc)rofi_theme_property_copy, NULL);\n    break;\n  case P_LINK:\n    retv->value.link.name = g_strdup(p->value.link.name);\n    retv->value.link.ref = NULL;\n    if (p->value.link.def_value) {\n      retv->value.link.def_value =\n          rofi_theme_property_copy(p->value.link.def_value, NULL);\n    }\n    break;\n  case P_PADDING: {\n    retv->value = p->value;\n    retv->value.padding.top =\n        rofi_theme_property_copy_distance(p->value.padding.top);\n    retv->value.padding.left =\n        rofi_theme_property_copy_distance(p->value.padding.left);\n    retv->value.padding.bottom =\n        rofi_theme_property_copy_distance(p->value.padding.bottom);\n    retv->value.padding.right =\n        rofi_theme_property_copy_distance(p->value.padding.right);\n    break;\n  }\n  case P_IMAGE: {\n    retv->value = p->value;\n    retv->value.image.url = g_strdup(p->value.image.url);\n    retv->value.image.colors = NULL;\n    for (GList *l = g_list_first(p->value.image.colors); l;\n         l = g_list_next(l)) {\n      retv->value.image.colors = g_list_append(\n          retv->value.image.colors, g_memdup2(l->data, sizeof(ThemeColor)));\n    }\n    break;\n  }\n  default:\n    retv->value = p->value;\n  }\n  return retv;\n}\n\nstatic void rofi_theme_distance_unit_property_free(RofiDistanceUnit *unit) {\n  if (unit->left) {\n    rofi_theme_distance_unit_property_free(unit->left);\n    unit->left = NULL;\n  }\n  if (unit->right) {\n    rofi_theme_distance_unit_property_free(unit->right);\n    unit->right = NULL;\n  }\n  g_slice_free(RofiDistanceUnit, unit);\n}\nstatic void rofi_theme_distance_property_free(RofiDistance *distance) {\n  if (distance->base.left) {\n    rofi_theme_distance_unit_property_free(distance->base.left);\n    distance->base.left = NULL;\n  }\n  if (distance->base.right) {\n    rofi_theme_distance_unit_property_free(distance->base.right);\n    distance->base.right = NULL;\n  }\n}\n\nvoid rofi_theme_property_free(Property *p) {\n  if (p == NULL) {\n    return;\n  }\n  g_free(p->name);\n  if (p->type == P_STRING) {\n    g_free(p->value.s);\n  } else if (p->type == P_LIST) {\n    g_list_free_full(p->value.list, (GDestroyNotify)rofi_theme_property_free);\n    p->value.list = 0;\n  } else if (p->type == P_LINK) {\n    g_free(p->value.link.name);\n    if (p->value.link.def_value) {\n      rofi_theme_property_free(p->value.link.def_value);\n    }\n  } else if (p->type == P_PADDING) {\n    rofi_theme_distance_property_free(&(p->value.padding.top));\n    rofi_theme_distance_property_free(&(p->value.padding.right));\n    rofi_theme_distance_property_free(&(p->value.padding.bottom));\n    rofi_theme_distance_property_free(&(p->value.padding.left));\n  } else if (p->type == P_IMAGE) {\n    if (p->value.image.url) {\n      g_free(p->value.image.url);\n    }\n    if (p->value.image.colors) {\n      g_list_free_full(p->value.image.colors, g_free);\n    }\n  }\n  g_slice_free(Property, p);\n}\n\nvoid rofi_theme_reset(void) {\n  rofi_theme_free(rofi_theme);\n  rofi_theme = g_slice_new0(ThemeWidget);\n  rofi_theme->name = g_strdup(\"Root\");\n}\n\nvoid rofi_theme_free(ThemeWidget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n  if (wid->properties) {\n    g_hash_table_destroy(wid->properties);\n    wid->properties = NULL;\n  }\n  if (wid->media) {\n    g_slice_free(ThemeMedia, wid->media);\n  }\n  for (unsigned int i = 0; i < wid->num_widgets; i++) {\n    rofi_theme_free(wid->widgets[i]);\n  }\n  g_free(wid->widgets);\n  g_free(wid->name);\n  g_slice_free(ThemeWidget, wid);\n}\n\n/**\n * print\n */\ninline static void printf_double(double d) {\n  char buf[G_ASCII_DTOSTR_BUF_SIZE + 1] = {\n      0,\n  };\n  g_ascii_formatd(buf, G_ASCII_DTOSTR_BUF_SIZE, \"%.4f\", d);\n  fputs(buf, stdout);\n}\n\nstatic void rofi_theme_print_distance_unit(RofiDistanceUnit *unit) {\n  if (unit->modtype == ROFI_DISTANCE_MODIFIER_GROUP) {\n    fputs(\"( \", stdout);\n  }\n  if (unit->left) {\n    rofi_theme_print_distance_unit(unit->left);\n  }\n\n  if (unit->modtype == ROFI_DISTANCE_MODIFIER_ADD) {\n    fputs(\" + \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_SUBTRACT) {\n    fputs(\" - \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_DIVIDE) {\n    fputs(\" / \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MULTIPLY) {\n    fputs(\" * \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MODULO) {\n    fputs(\" modulo \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MIN) {\n    fputs(\" min \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_MAX) {\n    fputs(\" max \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_ROUND) {\n    fputs(\" round \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_FLOOR) {\n    fputs(\" floor \", stdout);\n  } else if (unit->modtype == ROFI_DISTANCE_MODIFIER_CEIL) {\n    fputs(\" ceil \", stdout);\n  }\n  if (unit->right) {\n    rofi_theme_print_distance_unit(unit->right);\n  }\n\n  if (unit->modtype == ROFI_DISTANCE_MODIFIER_NONE) {\n    if (unit->type == ROFI_PU_PX) {\n      printf(\"%upx \", (unsigned int)unit->distance);\n    } else if (unit->type == ROFI_PU_MM) {\n      printf_double(unit->distance);\n      fputs(\"mm \", stdout);\n    } else if (unit->type == ROFI_PU_PERCENT) {\n      printf_double(unit->distance);\n      fputs(\"% \", stdout);\n    } else if (unit->type == ROFI_PU_CH) {\n      printf_double(unit->distance);\n      fputs(\"ch \", stdout);\n    } else {\n      printf_double(unit->distance);\n      fputs(\"em \", stdout);\n    }\n  }\n  if (unit->modtype == ROFI_DISTANCE_MODIFIER_GROUP) {\n    fputs(\" )\", stdout);\n  }\n}\n\nstatic void rofi_theme_print_color(ThemeColor color) {\n  uint8_t r, g, b;\n  g = 255 * color.green;\n  r = 255 * color.red;\n  b = 255 * color.blue;\n  if (color.alpha < 0.00001) {\n    printf(\"transparent\");\n    return;\n  }\n  for (uint32_t x = 0; x < num_CSSColors; x++) {\n    if (CSSColors[x].r == r && CSSColors[x].g == g && CSSColors[x].b == b) {\n      printf(\"%s\", CSSColors[x].name);\n      if (color.alpha < 1) {\n        printf(\"/%.0f%%\", color.alpha * 100.0);\n      }\n      return;\n    }\n  }\n  printf(\"rgba ( %.0f, %.0f, %.0f, %.0f %% )\", (color.red * 255.0),\n         (color.green * 255.0), (color.blue * 255.0), (color.alpha * 100.0));\n}\nstatic void rofi_theme_print_distance(RofiDistance d) {\n  if (d.base.modtype == ROFI_DISTANCE_MODIFIER_GROUP) {\n    fputs(\"calc( \", stdout);\n  }\n  rofi_theme_print_distance_unit(&(d.base));\n  if (d.base.modtype == ROFI_DISTANCE_MODIFIER_GROUP) {\n    fputs(\")\", stdout);\n  }\n  if (d.style == ROFI_HL_DASH) {\n    printf(\"dash \");\n  }\n}\n/** Textual representation of RofiCursorType */\nconst char *const RofiCursorTypeStr[3] = {\n    \"default\",\n    \"pointer\",\n    \"text\",\n};\n\nstatic void int_rofi_theme_print_property(Property *p) {\n  switch (p->type) {\n  case P_LIST:\n    printf(\"[ \");\n    for (GList *iter = p->value.list; iter != NULL; iter = g_list_next(iter)) {\n      int_rofi_theme_print_property((Property *)iter->data);\n      if (iter->next != NULL) {\n        printf(\",\");\n      }\n    }\n    printf(\" ]\");\n    break;\n  case P_ORIENTATION:\n    printf(\"%s\", (p->value.i == ROFI_ORIENTATION_HORIZONTAL) ? \"horizontal\"\n                                                             : \"vertical\");\n    break;\n  case P_CURSOR:\n    printf(\"%s\", RofiCursorTypeStr[p->value.i]);\n    break;\n  case P_HIGHLIGHT:\n    if (p->value.highlight.style & ROFI_HL_BOLD) {\n      printf(\"bold \");\n    }\n    if (p->value.highlight.style & ROFI_HL_UNDERLINE) {\n      printf(\"underline \");\n    }\n    if (p->value.highlight.style & ROFI_HL_STRIKETHROUGH) {\n      printf(\"strikethrough \");\n    }\n    if (p->value.highlight.style & ROFI_HL_ITALIC) {\n      printf(\"italic \");\n    }\n    if (p->value.highlight.style & ROFI_HL_UPPERCASE) {\n      printf(\"uppercase \");\n    }\n    if (p->value.highlight.style & ROFI_HL_LOWERCASE) {\n      printf(\"lowercase \");\n    }\n    if (p->value.highlight.style & ROFI_HL_CAPITALIZE) {\n      printf(\"capitalize \");\n    }\n    if (p->value.highlight.style & ROFI_HL_COLOR) {\n      rofi_theme_print_color(p->value.highlight.color);\n    }\n    break;\n  case P_POSITION: {\n    switch (p->value.i) {\n    case WL_CENTER:\n      fputs(\"center\", stdout);\n      break;\n    case WL_NORTH:\n      fputs(\"north\", stdout);\n      break;\n    case WL_SOUTH:\n      fputs(\"south\", stdout);\n      break;\n    case WL_WEST:\n      fputs(\"west\", stdout);\n      break;\n    case WL_EAST:\n      fputs(\"east\", stdout);\n      break;\n    case WL_NORTH | WL_EAST:\n      fputs(\"northeast\", stdout);\n      break;\n    case WL_SOUTH | WL_EAST:\n      fputs(\"southeast\", stdout);\n      break;\n    case WL_NORTH | WL_WEST:\n      fputs(\"northwest\", stdout);\n      break;\n    case WL_SOUTH | WL_WEST:\n      fputs(\"southwest\", stdout);\n      break;\n    }\n    break;\n  }\n  case P_STRING:\n    printf(\"\\\"%s\\\"\", p->value.s);\n    break;\n  case P_INTEGER:\n    printf(\"%d\", p->value.i);\n    break;\n  case P_DOUBLE: {\n    char sign = (p->value.f < 0);\n    int top = (int)fabs(p->value.f);\n    int bottom = (fabs(fmod(p->value.f, 1.0))) * 100;\n    printf(\"%s%d.%02d\", sign ? \"-\" : \"\", top, bottom);\n    break;\n  }\n  case P_BOOLEAN:\n    printf(\"%s\", p->value.b ? \"true\" : \"false\");\n    break;\n  case P_COLOR:\n    rofi_theme_print_color(p->value.color);\n    break;\n  case P_IMAGE: {\n    if (p->value.image.type == ROFI_IMAGE_URL) {\n      printf(\"url (\\\"%s\\\")\", p->value.s);\n    } else if (p->value.image.type == ROFI_IMAGE_LINEAR_GRADIENT) {\n      printf(\"linear-gradient ( \");\n      guint length = g_list_length(p->value.image.colors);\n      guint index = 0;\n      for (GList *l = g_list_first(p->value.image.colors); l != NULL;\n           l = g_list_next(l)) {\n        ThemeColor *color = (ThemeColor *)l->data;\n        rofi_theme_print_color(*color);\n        index++;\n        if (index < length) {\n          printf(\", \");\n        }\n      }\n      printf(\")\");\n    }\n\n    break;\n  }\n  case P_PADDING:\n    if (distance_compare(p->value.padding.top, p->value.padding.bottom) &&\n        distance_compare(p->value.padding.left, p->value.padding.right) &&\n        distance_compare(p->value.padding.left, p->value.padding.top)) {\n      rofi_theme_print_distance(p->value.padding.left);\n    } else if (distance_compare(p->value.padding.top,\n                                p->value.padding.bottom) &&\n               distance_compare(p->value.padding.left,\n                                p->value.padding.right)) {\n      rofi_theme_print_distance(p->value.padding.top);\n      rofi_theme_print_distance(p->value.padding.left);\n    } else if (!distance_compare(p->value.padding.top,\n                                 p->value.padding.bottom) &&\n               distance_compare(p->value.padding.left,\n                                p->value.padding.right)) {\n      rofi_theme_print_distance(p->value.padding.top);\n      rofi_theme_print_distance(p->value.padding.left);\n      rofi_theme_print_distance(p->value.padding.bottom);\n    } else {\n      rofi_theme_print_distance(p->value.padding.top);\n      rofi_theme_print_distance(p->value.padding.right);\n      rofi_theme_print_distance(p->value.padding.bottom);\n      rofi_theme_print_distance(p->value.padding.left);\n    }\n    break;\n  case P_LINK:\n    if (p->value.link.def_value) {\n      printf(\"var( %s, \", p->value.link.name);\n      int_rofi_theme_print_property(p->value.link.def_value);\n      printf(\")\");\n    } else {\n      printf(\"var(%s)\", p->value.link.name);\n    }\n    break;\n  case P_INHERIT:\n    printf(\"inherit\");\n    break;\n  default:\n    break;\n  }\n}\n\nstatic void rofi_theme_print_property_index(size_t pnl, int cur_depth,\n                                            Property *p) {\n  int pl = strlen(p->name);\n  printf(\"%*s%s:%*s \", cur_depth, \"\", p->name, (int)pnl - pl, \"\");\n  int_rofi_theme_print_property(p);\n  putchar(';');\n  putchar('\\n');\n}\n\nvoid rofi_theme_print_index(ThemeWidget *wid, int index) {\n  GHashTableIter iter;\n  gpointer key, value;\n\n  if (wid->media) {\n    printf(\"%s {\\n\", wid->name);\n    for (unsigned int i = 0; i < wid->num_widgets; i++) {\n      rofi_theme_print_index(wid->widgets[i], index + 4);\n    }\n    printf(\"}\\n\");\n  } else {\n    if (wid->properties) {\n      GList *list = NULL;\n      ThemeWidget *w = wid;\n      while (w) {\n        if (g_strcmp0(w->name, \"Root\") == 0) {\n          break;\n        }\n        if (w->media) {\n          break;\n        }\n        list = g_list_prepend(list, w->name);\n        w = w->parent;\n      }\n      if (g_list_length(list) > 0) {\n        printf(\"%*s\", index, \"\");\n        for (GList *citer = g_list_first(list); citer != NULL;\n             citer = g_list_next(citer)) {\n          char *name = (char *)citer->data;\n          fputs(name, stdout);\n          if (citer->prev == NULL && citer->next) {\n            putchar(' ');\n          } else if (citer->next) {\n            putchar('.');\n          }\n        }\n        printf(\" {\\n\");\n      } else {\n        printf(\"%*s* {\\n\", index, \"\");\n      }\n      size_t property_name_length = 0;\n      g_hash_table_iter_init(&iter, wid->properties);\n      while (g_hash_table_iter_next(&iter, &key, &value)) {\n        Property *pv = (Property *)value;\n        property_name_length = MAX(strlen(pv->name), property_name_length);\n      }\n      g_hash_table_iter_init(&iter, wid->properties);\n      while (g_hash_table_iter_next(&iter, &key, &value)) {\n        Property *pv = (Property *)value;\n        rofi_theme_print_property_index(property_name_length, index + 4, pv);\n      }\n      printf(\"%*s}\\n\", index, \"\");\n      g_list_free(list);\n    }\n    for (unsigned int i = 0; i < wid->num_widgets; i++) {\n      rofi_theme_print_index(wid->widgets[i], index);\n    }\n  }\n}\n\nvoid rofi_theme_print(ThemeWidget *wid) {\n  if (wid != NULL) {\n    printf(\"/**\\n * rofi -dump-theme output.\\n * Rofi version: %s\\n **/\\n\",\n           PACKAGE_VERSION);\n    rofi_theme_print_index(wid, 0);\n  }\n}\n\n/**\n * Destroy the internal of lex parser.\n */\nvoid yylex_destroy(void);\n\n/**\n * Global handle input file to flex parser.\n */\nextern FILE *yyin;\n\n/**\n * @param yylloc The file location.\n * @param what   What we are parsing, filename or string.\n * @param s      Error message string.\n *\n * Error handler for the lex parser.\n */\nvoid yyerror(YYLTYPE *yylloc, const char *what, const char *s) {\n  char *what_esc = what ? g_markup_escape_text(what, -1) : g_strdup(\"\");\n  GString *str = g_string_new(\"\");\n  g_string_printf(str,\n                  \"<big><b>Error while parsing theme:</b></big> <i>%s</i>\\n\",\n                  what_esc);\n  g_free(what_esc);\n  char *esc = g_markup_escape_text(s, -1);\n  g_string_append_printf(\n      str,\n      \"\\tParser error: <span size=\\\"smaller\\\" style=\\\"italic\\\">%s</span>\\n\",\n      esc);\n  g_free(esc);\n  if (yylloc->filename != NULL) {\n    g_string_append_printf(\n        str,\n        \"\\tLocation:     line %d column %d to line %d column %d.\\n\"\n        \"\\tFile          '%s'\\n\",\n        yylloc->first_line, yylloc->first_column, yylloc->last_line,\n        yylloc->last_column, yylloc->filename);\n  } else {\n    g_string_append_printf(\n        str, \"\\tLocation:     line %d column %d to line %d column %d\\n\",\n        yylloc->first_line, yylloc->first_column, yylloc->last_line,\n        yylloc->last_column);\n  }\n  g_log(\"Parser\", G_LOG_LEVEL_DEBUG, \"Failed to parse theme:\\n%s\", str->str);\n  rofi_add_error_message(str);\n}\n\nstatic void rofi_theme_copy_property_int(G_GNUC_UNUSED gpointer key,\n                                         gpointer value, gpointer user_data) {\n  GHashTable *table = (GHashTable *)user_data;\n  Property *p = rofi_theme_property_copy((Property *)value, NULL);\n  g_hash_table_replace(table, p->name, p);\n}\nvoid rofi_theme_widget_add_properties(ThemeWidget *wid, GHashTable *table) {\n  if (table == NULL) {\n    return;\n  }\n  if (wid->properties == NULL) {\n    wid->properties =\n        g_hash_table_new_full(g_str_hash, g_str_equal, NULL,\n                              (GDestroyNotify)rofi_theme_property_free);\n  }\n  g_hash_table_foreach(table, rofi_theme_copy_property_int, wid->properties);\n}\n\n/**\n * Public API\n */\n\nstatic inline ThemeWidget *rofi_theme_find_single(ThemeWidget *wid,\n                                                  const char *name) {\n  for (unsigned int j = 0; wid && j < wid->num_widgets; j++) {\n    if (g_strcmp0(wid->widgets[j]->name, name) == 0) {\n      return wid->widgets[j];\n    }\n  }\n  return wid;\n}\n\nstatic ThemeWidget *rofi_theme_find(ThemeWidget *wid, const char *name,\n                                    const gboolean exact) {\n  if (wid == NULL || name == NULL) {\n    return wid;\n  }\n  char *tname = g_strdup(name);\n  char *saveptr = NULL;\n  int found = TRUE;\n  for (const char *iter = strtok_r(tname, \".\", &saveptr); iter != NULL;\n       iter = strtok_r(NULL, \".\", &saveptr)) {\n    found = FALSE;\n    ThemeWidget *f = rofi_theme_find_single(wid, iter);\n    if (f != wid) {\n      wid = f;\n      found = TRUE;\n    } else if (exact) {\n      break;\n    }\n  }\n  g_free(tname);\n  if (!exact || found) {\n    return wid;\n  }\n  return NULL;\n}\n\nstatic void rofi_theme_resolve_link_property(Property *p, int cur_depth) {\n  // Set name, remove '@' prefix.\n  const char *name = p->value.link.name; // + (*(p->value.link.name)== '@'?1:0;\n  g_info(\"Resolving link to %s\", p->value.link.name);\n  if (cur_depth > 20) {\n    g_warning(\"Found more then 20 redirects for property. Stopping.\");\n    p->value.link.ref = p;\n    return;\n  }\n\n  if (rofi_theme->properties &&\n      g_hash_table_contains(rofi_theme->properties, name)) {\n    Property *pr = g_hash_table_lookup(rofi_theme->properties, name);\n    g_info(\"Resolving link %s found: %s\", p->value.link.name, pr->name);\n    if (pr->type == P_LINK) {\n      if (pr->value.link.ref == NULL) {\n        rofi_theme_resolve_link_property(pr, cur_depth + 1);\n      }\n      if (pr->value.link.ref != pr) {\n        p->value.link.ref = pr->value.link.ref;\n        return;\n      }\n    } else {\n      p->value.link.ref = pr;\n      return;\n    }\n  }\n  // No found and we have default value.\n  if (p->value.link.def_value) {\n    p->value.link.ref = p->value.link.def_value;\n    return;\n  }\n\n  // No found, set ref to self.\n  p->value.link.ref = p;\n}\n\nProperty *rofi_theme_find_property(ThemeWidget *wid, PropertyType type,\n                                   const char *property, gboolean exact) {\n  while (wid) {\n    if (wid->properties && g_hash_table_contains(wid->properties, property)) {\n      Property *p = g_hash_table_lookup(wid->properties, property);\n      if (p->type == P_INHERIT) {\n        return p;\n      }\n      if (p->type == P_LINK) {\n        if (p->value.link.ref == NULL) {\n          // Resolve link.\n          rofi_theme_resolve_link_property(p, 0);\n        }\n        if (p->value.link.ref != NULL && p->value.link.ref->type == type) {\n          return p->value.link.ref;\n        }\n      }\n      if (p->type == type) {\n        return p;\n      }\n      // RofiPadding and integer can be converted.\n      if (p->type == P_INTEGER && type == P_PADDING) {\n        return p;\n      }\n      g_debug(\"Found property: '%s' on '%s', but type %s does not match \"\n              \"expected type %s.\",\n              property, wid->name, PropertyTypeName[p->type],\n              PropertyTypeName[type]);\n    }\n    if (exact) {\n      return NULL;\n    }\n    // Fall back to defaults.\n    wid = wid->parent;\n  }\n  return NULL;\n}\nThemeWidget *rofi_config_find_widget(const char *name, const char *state,\n                                     gboolean exact) {\n  // First find exact match based on name.\n  ThemeWidget *wid = rofi_theme_find_single(rofi_configuration, name);\n  wid = rofi_theme_find(wid, state, exact);\n\n  return wid;\n}\nThemeWidget *rofi_theme_find_widget(const char *name, const char *state,\n                                    gboolean exact) {\n  // First find exact match based on name.\n  ThemeWidget *wid = rofi_theme_find_single(rofi_theme, name);\n  wid = rofi_theme_find(wid, state, exact);\n\n  return wid;\n}\n\nstatic int rofi_theme_get_position_inside(Property *p, const widget *wid,\n                                          const char *property, int def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_POSITION, property, FALSE);\n        return rofi_theme_get_position_inside(pv, wid->parent, property, def);\n      }\n      return def;\n    }\n    return p->value.i;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nint rofi_theme_get_position(const widget *wid, const char *property, int def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_POSITION, property, FALSE);\n  return rofi_theme_get_position_inside(p, wid, property, def);\n}\nstatic int rofi_theme_get_integer_inside(Property *p, const widget *wid,\n                                         const char *property, int def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_INTEGER, property, FALSE);\n        return rofi_theme_get_integer_inside(pv, wid->parent, property, def);\n      }\n      return def;\n    }\n    return p->value.i;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nint rofi_theme_get_integer(const widget *wid, const char *property, int def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_INTEGER, property, FALSE);\n  return (int)rofi_theme_get_integer_inside(p, wid, property, (double)def);\n}\nstatic RofiDistance rofi_theme_get_distance_inside(Property *p,\n                                                   const widget *wid,\n                                                   const char *property,\n                                                   int def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_PADDING, property, FALSE);\n        return rofi_theme_get_distance_inside(pv, wid->parent, property, def);\n      }\n      return (RofiDistance){\n          .base = {def, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},\n          .style = ROFI_HL_SOLID};\n    }\n    if (p->type == P_INTEGER) {\n      return (RofiDistance){.base = {p->value.i, ROFI_PU_PX,\n                                     ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},\n                            .style = ROFI_HL_SOLID};\n    }\n    return p->value.padding.left;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return (RofiDistance){\n      .base = {def, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},\n      .style = ROFI_HL_SOLID};\n}\nRofiDistance rofi_theme_get_distance(const widget *wid, const char *property,\n                                     int def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_PADDING, property, FALSE);\n  return rofi_theme_get_distance_inside(p, wid, property, def);\n}\n\nstatic int rofi_theme_get_boolean_inside(Property *p, const widget *wid,\n                                         const char *property, int def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_BOOLEAN, property, FALSE);\n        return rofi_theme_get_boolean_inside(pv, wid->parent, property, def);\n      }\n      return def;\n    }\n    return p->value.b;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nint rofi_theme_get_boolean(const widget *wid, const char *property, int def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_BOOLEAN, property, FALSE);\n  return rofi_theme_get_boolean_inside(p, wid, property, def);\n}\n\nstatic RofiOrientation rofi_theme_get_orientation_inside(Property *p,\n                                                         const widget *wid,\n                                                         const char *property,\n                                                         RofiOrientation def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_ORIENTATION, property, FALSE);\n        return rofi_theme_get_orientation_inside(pv, wid->parent, property,\n                                                 def);\n      }\n      return def;\n    }\n    return p->value.b;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nRofiOrientation rofi_theme_get_orientation(const widget *wid,\n                                           const char *property,\n                                           RofiOrientation def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p =\n      rofi_theme_find_property(wid_find, P_ORIENTATION, property, FALSE);\n  return rofi_theme_get_orientation_inside(p, wid, property, def);\n}\n\nstatic RofiCursorType rofi_theme_get_cursor_type_inside(Property *p,\n                                                        const widget *wid,\n                                                        const char *property,\n                                                        RofiCursorType def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_CURSOR, property, FALSE);\n        return rofi_theme_get_cursor_type_inside(pv, wid->parent, property,\n                                                 def);\n      }\n      return def;\n    }\n    return p->value.i;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nRofiCursorType rofi_theme_get_cursor_type(const widget *wid,\n                                          const char *property,\n                                          RofiCursorType def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_CURSOR, property, FALSE);\n  return rofi_theme_get_cursor_type_inside(p, wid, property, def);\n}\nstatic const char *rofi_theme_get_string_inside(Property *p, const widget *wid,\n                                                const char *property,\n                                                const char *def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_STRING, property, FALSE);\n        return rofi_theme_get_string_inside(pv, wid->parent, property, def);\n      }\n      return def;\n    }\n    return p->value.s;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nconst char *rofi_theme_get_string(const widget *wid, const char *property,\n                                  const char *def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_STRING, property, FALSE);\n  return rofi_theme_get_string_inside(p, wid, property, def);\n}\n\nstatic double rofi_theme_get_double_integer_fb_inside(Property *p,\n                                                      const widget *wid,\n                                                      const char *property,\n                                                      double def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_INTEGER, property, FALSE);\n        return rofi_theme_get_double_integer_fb_inside(pv, wid->parent,\n                                                       property, def);\n      }\n      return def;\n    }\n    return p->value.i;\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return def;\n}\nstatic double rofi_theme_get_double_inside(const widget *orig, Property *p,\n                                           const widget *wid,\n                                           const char *property, double def) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_DOUBLE, property, FALSE);\n        return rofi_theme_get_double_inside(orig, pv, wid->parent, property,\n                                            def);\n      }\n      return def;\n    }\n    return p->value.f;\n  }\n  ThemeWidget *wid_find = rofi_theme_find_widget(orig->name, wid->state, FALSE);\n  // Fallback to integer if double is not found.\n  p = rofi_theme_find_property(wid_find, P_INTEGER, property, FALSE);\n  return rofi_theme_get_double_integer_fb_inside(p, wid, property, def);\n}\ndouble rofi_theme_get_double(const widget *wid, const char *property,\n                             double def) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_DOUBLE, property, FALSE);\n  return rofi_theme_get_double_inside(wid, p, wid, property, def);\n}\nstatic void rofi_theme_get_color_inside(const widget *wid, Property *p,\n                                        const char *property, cairo_t *d) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_COLOR, property, FALSE);\n        rofi_theme_get_color_inside(wid->parent, pv, property, d);\n      }\n      return;\n    }\n    cairo_set_source_rgba(d, p->value.color.red, p->value.color.green,\n                          p->value.color.blue, p->value.color.alpha);\n  } else {\n    g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n            wid->state ? wid->state : \"\", property);\n  }\n}\n\nvoid rofi_theme_get_color(const widget *wid, const char *property, cairo_t *d) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_COLOR, property, FALSE);\n  rofi_theme_get_color_inside(wid, p, property, d);\n}\n\nstatic gboolean rofi_theme_get_image_inside(Property *p, const widget *wid,\n                                            const char *property, cairo_t *d) {\n  const guint scale = disp_scale ? disp_scale() : 1;\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_IMAGE, property, FALSE);\n        return rofi_theme_get_image_inside(pv, wid->parent, property, d);\n      }\n      return FALSE;\n    }\n    if (p->value.image.type == ROFI_IMAGE_URL) {\n      int wsize = -1;\n      int hsize = -1;\n      switch (p->value.image.scaling) {\n      case ROFI_SCALE_BOTH:\n        wsize = wid->w;\n        hsize = wid->h;\n        break;\n      case ROFI_SCALE_WIDTH:\n        wsize = wid->w;\n        break;\n      case ROFI_SCALE_HEIGHT:\n        hsize = wid->h;\n        break;\n      case ROFI_SCALE_NONE:\n      default:\n        break;\n      }\n      // FIXME: cache when hsize, wsize and scale do not change without\n      // modifying RofiImage (for ABI compatibility)\n      p->value.image.surface_id =\n          rofi_icon_fetcher_query_advanced(p->value.image.url, wsize, hsize);\n      cairo_surface_t *img = rofi_icon_fetcher_get(p->value.image.surface_id);\n\n      if (img != NULL) {\n        cairo_pattern_t *pat = cairo_pattern_create_for_surface(img);\n        cairo_surface_set_device_scale(img, scale, scale);\n        cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT);\n        cairo_set_source(d, pat);\n        cairo_pattern_destroy(pat);\n        return TRUE;\n      }\n    } else if (p->value.image.type == ROFI_IMAGE_LINEAR_GRADIENT) {\n      cairo_pattern_t *pat = NULL;\n      switch (p->value.image.dir) {\n      case ROFI_DIRECTION_RIGHT:\n        pat = cairo_pattern_create_linear(0.0, 0.0, wid->w, 0.0);\n        break;\n      case ROFI_DIRECTION_LEFT:\n        pat = cairo_pattern_create_linear(wid->w, 0.0, 0.0, 0.0);\n        break;\n      case ROFI_DIRECTION_BOTTOM:\n        pat = cairo_pattern_create_linear(0.0, 0.0, 0.0, wid->h);\n        break;\n      case ROFI_DIRECTION_TOP:\n        pat = cairo_pattern_create_linear(0.0, wid->h, 0.0, 0.0);\n        break;\n      case ROFI_DIRECTION_ANGLE: {\n        double offsety1 = sin(G_PI * 2 * p->value.image.angle) * (wid->h / 2.0);\n        double offsetx1 = cos(G_PI * 2 * p->value.image.angle) * (wid->w / 2.0);\n        pat = cairo_pattern_create_linear(\n            wid->w / 2.0 - offsetx1, wid->h / 2.0 - offsety1,\n            wid->w / 2.0 + offsetx1, wid->h / 2.0 + offsety1);\n        break;\n      }\n      };\n      guint length = g_list_length(p->value.image.colors);\n      if (length > 1) {\n        length--;\n        guint color_index = 0;\n        for (GList *l = g_list_first(p->value.image.colors); l != NULL;\n             l = g_list_next(l)) {\n          ThemeColor *c = (ThemeColor *)(l->data);\n          cairo_pattern_add_color_stop_rgba(pat, (color_index) / (double)length,\n                                            c->red, c->green, c->blue,\n                                            c->alpha);\n          color_index++;\n        }\n        cairo_set_source(d, pat);\n        cairo_pattern_destroy(pat);\n        return TRUE;\n      }\n      if (length == 1) {\n        ThemeColor *c = (ThemeColor *)(p->value.image.colors->data);\n        cairo_pattern_add_color_stop_rgba(pat, 0, c->red, c->green, c->blue,\n                                          c->alpha);\n        cairo_set_source(d, pat);\n        cairo_pattern_destroy(pat);\n        return TRUE;\n      }\n    }\n  } else {\n    g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n            wid->state ? wid->state : \"\", property);\n  }\n  return FALSE;\n}\ngboolean rofi_theme_get_image(const widget *wid, const char *property,\n                              cairo_t *d) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_IMAGE, property, FALSE);\n  return rofi_theme_get_image_inside(p, wid, property, d);\n}\nstatic RofiPadding rofi_theme_get_padding_inside(Property *p, const widget *wid,\n                                                 const char *property,\n                                                 RofiPadding pad) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_PADDING, property, FALSE);\n        return rofi_theme_get_padding_inside(pv, wid->parent, property, pad);\n      }\n      return pad;\n    }\n    if (p->type == P_PADDING) {\n      pad = p->value.padding;\n    } else {\n      RofiDistance d =\n          (RofiDistance){.base = {p->value.i, ROFI_PU_PX,\n                                  ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},\n                         .style = ROFI_HL_SOLID};\n      return (RofiPadding){d, d, d, d};\n    }\n  }\n  g_debug(\"Theme entry: #%s %s property %s unset.\", wid->name,\n          wid->state ? wid->state : \"\", property);\n  return pad;\n}\nRofiPadding rofi_theme_get_padding(const widget *wid, const char *property,\n                                   RofiPadding pad) {\n  ThemeWidget *wid_find = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid_find, P_PADDING, property, FALSE);\n  return rofi_theme_get_padding_inside(p, wid, property, pad);\n}\n\nstatic GList *rofi_theme_get_list_inside(Property *p, const widget *wid,\n                                         const char *property,\n                                         PropertyType child_type) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_LIST, property, FALSE);\n        return rofi_theme_get_list_inside(pv, wid->parent, property,\n                                          child_type);\n      }\n    } else if (p->type == P_LIST) {\n      return p->value.list;\n    }\n  }\n  return NULL;\n}\nGList *rofi_theme_get_list_distance(const widget *wid, const char *property) {\n  ThemeWidget *wid2 = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid2, P_LIST, property, FALSE);\n  GList *list = rofi_theme_get_list_inside(p, wid, property, P_PADDING);\n  GList *retv = NULL;\n  for (GList *iter = g_list_first(list); iter != NULL;\n       iter = g_list_next(iter)) {\n    Property *prop = (Property *)(iter->data);\n    if (prop->type == P_PADDING) {\n      RofiDistance *pnew = g_new0(RofiDistance, 1);\n      *pnew = prop->value.padding.left;\n      retv = g_list_append(retv, pnew);\n    } else if (prop->type == P_INTEGER) {\n      RofiDistance *pnew = g_new0(RofiDistance, 1);\n      RofiDistance d =\n          (RofiDistance){.base = {prop->value.i, ROFI_PU_PX,\n                                  ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL},\n                         .style = ROFI_HL_SOLID};\n      *pnew = d;\n      retv = g_list_append(retv, pnew);\n    } else {\n      g_warning(\"Invalid type detected in list.\");\n    }\n  }\n  return retv;\n}\nGList *rofi_theme_get_list_strings(const widget *wid, const char *property) {\n  ThemeWidget *wid2 = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p = rofi_theme_find_property(wid2, P_LIST, property, FALSE);\n  GList *list = rofi_theme_get_list_inside(p, wid, property, P_STRING);\n  GList *retv = NULL;\n  for (GList *iter = g_list_first(list); iter != NULL;\n       iter = g_list_next(iter)) {\n    Property *prop = (Property *)(iter->data);\n    if (prop->type == P_STRING) {\n      retv = g_list_append(retv, g_strdup(prop->value.s));\n    } else {\n      g_warning(\"Invalid type detected in list.\");\n    }\n  }\n  return retv;\n}\n\nstatic RofiHighlightColorStyle\nrofi_theme_get_highlight_inside(Property *p, widget *wid, const char *property,\n                                RofiHighlightColorStyle th) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid->parent->name, wid->state, FALSE);\n        Property *pv =\n            rofi_theme_find_property(parent, P_HIGHLIGHT, property, FALSE);\n        return rofi_theme_get_highlight_inside(pv, wid->parent, property, th);\n      }\n      return th;\n    } else if (p->type == P_COLOR) {\n      th.style = ROFI_HL_NONE | ROFI_HL_COLOR;\n      th.color = p->value.color;\n      return th;\n    }\n\n    return p->value.highlight;\n  } else {\n    ThemeWidget *find_wid =\n        rofi_theme_find_widget(wid->name, wid->state, FALSE);\n    Property *p2 = rofi_theme_find_property(find_wid, P_COLOR, property, FALSE);\n    if (p2 != NULL) {\n      return rofi_theme_get_highlight_inside(p2, wid, property, th);\n    }\n    return th;\n  }\n  // UNREACHABLE\n}\nRofiHighlightColorStyle rofi_theme_get_highlight(widget *wid,\n                                                 const char *property,\n                                                 RofiHighlightColorStyle th) {\n  ThemeWidget *found_wid = rofi_theme_find_widget(wid->name, wid->state, FALSE);\n  Property *p =\n      rofi_theme_find_property(found_wid, P_HIGHLIGHT, property, FALSE);\n  if (p == NULL) {\n    p = rofi_theme_find_property(found_wid, P_COLOR, property, FALSE);\n  }\n  return rofi_theme_get_highlight_inside(p, wid, property, th);\n}\nstatic double get_pixels(RofiDistanceUnit *unit, RofiOrientation ori) {\n  double val = unit->distance;\n\n  if (unit->type == ROFI_PU_EM) {\n    val = unit->distance * textbox_get_estimated_char_height();\n  } else if (unit->type == ROFI_PU_CH) {\n    val = unit->distance * textbox_get_estimated_ch();\n  } else if (unit->type == ROFI_PU_PERCENT) {\n    if (ori == ROFI_ORIENTATION_VERTICAL) {\n      int height = 0;\n      rofi_view_get_current_monitor(NULL, &height);\n      val = (unit->distance * height) / (100.0);\n    } else {\n      int width = 0;\n      rofi_view_get_current_monitor(&width, NULL);\n      val = (unit->distance * width) / (100.0);\n    }\n  } else if (unit->type == ROFI_PU_MM) {\n    val = unit->distance * config.dpi / 25.4;\n  }\n  return val;\n}\n\nstatic double distance_unit_get_pixel(RofiDistanceUnit *unit,\n                                      RofiOrientation ori) {\n  switch (unit->modtype) {\n  case ROFI_DISTANCE_MODIFIER_GROUP:\n    return distance_unit_get_pixel(unit->left, ori);\n    break;\n  case ROFI_DISTANCE_MODIFIER_ADD:\n    return distance_unit_get_pixel(unit->left, ori) +\n           distance_unit_get_pixel(unit->right, ori);\n  case ROFI_DISTANCE_MODIFIER_SUBTRACT:\n    return distance_unit_get_pixel(unit->left, ori) -\n           distance_unit_get_pixel(unit->right, ori);\n  case ROFI_DISTANCE_MODIFIER_MULTIPLY:\n    return distance_unit_get_pixel(unit->left, ori) *\n           distance_unit_get_pixel(unit->right, ori);\n  case ROFI_DISTANCE_MODIFIER_DIVIDE: {\n    double a = distance_unit_get_pixel(unit->left, ori);\n    double b = distance_unit_get_pixel(unit->right, ori);\n    if (b != 0) {\n      return a / b;\n    }\n    return a;\n  }\n  case ROFI_DISTANCE_MODIFIER_MODULO: {\n    double a = distance_unit_get_pixel(unit->left, ori);\n    double b = distance_unit_get_pixel(unit->right, ori);\n    if (b != 0) {\n      return fmod(a, b);\n    }\n    return 0;\n  }\n  case ROFI_DISTANCE_MODIFIER_MIN: {\n    double a = distance_unit_get_pixel(unit->left, ori);\n    double b = distance_unit_get_pixel(unit->right, ori);\n    return MIN(a, b);\n  }\n  case ROFI_DISTANCE_MODIFIER_MAX: {\n    double a = distance_unit_get_pixel(unit->left, ori);\n    double b = distance_unit_get_pixel(unit->right, ori);\n    return MAX(a, b);\n  }\n  case ROFI_DISTANCE_MODIFIER_ROUND: {\n    double a = (double)distance_unit_get_pixel(unit->left, ori);\n    double b = (double)distance_unit_get_pixel(unit->right, ori);\n    return (double)(round(a / b) * b);\n  }\n  case ROFI_DISTANCE_MODIFIER_CEIL: {\n    double a = (double)distance_unit_get_pixel(unit->left, ori);\n    double b = (double)distance_unit_get_pixel(unit->right, ori);\n    return (double)(ceil(a / b) * b);\n  }\n  case ROFI_DISTANCE_MODIFIER_FLOOR: {\n    double a = (double)distance_unit_get_pixel(unit->left, ori);\n    double b = (double)distance_unit_get_pixel(unit->right, ori);\n    return (double)(floor(a / b) * b);\n  }\n  default:\n    break;\n  }\n  return get_pixels(unit, ori);\n}\n\nint distance_get_pixel(RofiDistance d, RofiOrientation ori) {\n  return distance_unit_get_pixel(&(d.base), ori);\n}\n\nvoid distance_get_linestyle(RofiDistance d, cairo_t *draw) {\n  if (d.style == ROFI_HL_DASH) {\n    const double dashes[1] = {4};\n    cairo_set_dash(draw, dashes, 1, 0.0);\n  } else {\n    cairo_set_dash(draw, NULL, 0, 0.0);\n  }\n}\n\nchar *rofi_theme_parse_prepare_file(const char *file) {\n  char *filename = g_strdup(file);\n  // TODO: Why did I write this code? I think it was to get full path.\n  GFile *gf = g_file_new_for_path(filename);\n  parsed_config_files = g_list_append(parsed_config_files, filename);\n  filename = g_file_get_path(gf);\n  g_object_unref(gf);\n\n  return filename;\n}\n\nvoid rofi_theme_parse_merge_widgets(ThemeWidget *parent, ThemeWidget *child) {\n  g_assert(parent != NULL);\n  g_assert(child != NULL);\n\n  if (parent == rofi_theme && g_strcmp0(child->name, \"*\") == 0) {\n    rofi_theme_widget_add_properties(parent, child->properties);\n    return;\n  }\n\n  ThemeWidget *w = rofi_theme_find_or_create_name(parent, child->name);\n  if (child->media) {\n    w->media = g_slice_new0(ThemeMedia);\n    *(w->media) = *(child->media);\n  }\n  rofi_theme_widget_add_properties(w, child->properties);\n  for (unsigned int i = 0; i < child->num_widgets; i++) {\n    rofi_theme_parse_merge_widgets(w, child->widgets[i]);\n  }\n}\n\nstatic void rofi_theme_parse_process_conditionals_int(workarea mon,\n                                                      ThemeWidget *rwidget) {\n  if (rwidget == NULL) {\n    return;\n  }\n  unsigned int i = 0;\n  //  for (unsigned int i = 0; i < rwidget->num_widgets; i++) {\n  while (i < rwidget->num_widgets) {\n    ThemeWidget *child_widget = rwidget->widgets[i];\n    if (child_widget->media != NULL) {\n      rwidget->num_widgets--;\n      for (unsigned x = i; x < rwidget->num_widgets; x++) {\n        rwidget->widgets[x] = rwidget->widgets[x + 1];\n      }\n      rwidget->widgets[rwidget->num_widgets] = NULL;\n      switch (child_widget->media->type) {\n      case THEME_MEDIA_TYPE_MIN_WIDTH: {\n        int w = child_widget->media->value;\n        if (mon.w >= w) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MAX_WIDTH: {\n        int w = child_widget->media->value;\n        if (mon.w < w) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MIN_HEIGHT: {\n        int h = child_widget->media->value;\n        if (mon.h >= h) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        } else {\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MAX_HEIGHT: {\n        int h = child_widget->media->value;\n        if (mon.h < h) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MON_ID: {\n        if (mon.monitor_id == child_widget->media->value) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MIN_ASPECT_RATIO: {\n        double r = child_widget->media->value;\n        if ((mon.w / (double)mon.h) >= r) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_MAX_ASPECT_RATIO: {\n        double r = child_widget->media->value;\n        if ((mon.w / (double)mon.h) < r) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n      case THEME_MEDIA_TYPE_BOOLEAN: {\n        if (child_widget->media->boolv) {\n          for (unsigned int x = 0; x < child_widget->num_widgets; x++) {\n            rofi_theme_parse_merge_widgets(rwidget, child_widget->widgets[x]);\n          }\n        }\n        break;\n      }\n\n      default: {\n        break;\n      }\n      }\n      rofi_theme_free(child_widget);\n      // endif\n    } else {\n      rofi_theme_parse_process_conditionals_int(mon, child_widget);\n      i++;\n    }\n  }\n}\n\nstatic char *rofi_theme_widget_get_name(ThemeWidget *wid) {\n  GString *str = g_string_new(wid->name);\n  for (ThemeWidget *i = wid->parent; i->parent != NULL; i = i->parent) {\n    g_string_prepend_c(str, ' ');\n    g_string_prepend(str, i->name);\n  }\n  char *retv = str->str;\n  g_string_free(str, FALSE);\n  return retv;\n}\n\nstatic void rofi_theme_parse_process_links_int(ThemeWidget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n\n  for (unsigned int i = 0; i < wid->num_widgets; i++) {\n    ThemeWidget *child_widget = wid->widgets[i];\n    rofi_theme_parse_process_links_int(child_widget);\n    if (child_widget->properties == NULL) {\n      continue;\n    }\n    GHashTableIter iter;\n    gpointer key, value;\n    g_hash_table_iter_init(&iter, child_widget->properties);\n    while (g_hash_table_iter_next(&iter, &key, &value)) {\n      Property *pv = (Property *)value;\n      if (pv->type == P_LINK) {\n        if (pv->value.link.ref == NULL) {\n          rofi_theme_resolve_link_property(pv, 0);\n          if (pv->value.link.ref == pv) {\n            char *n = rofi_theme_widget_get_name(child_widget);\n            GString *str = g_string_new(NULL);\n            g_string_printf(str,\n                            \"Validating the theme failed: the variable '%s' in \"\n                            \"`%s { %s: var(%s);}` failed to resolve.\",\n                            pv->value.link.name, n, pv->name,\n                            pv->value.link.name);\n\n            rofi_add_warning_message(str);\n            g_free(n);\n          }\n        }\n      }\n    }\n  }\n}\n\nvoid rofi_theme_parse_process_links(void) {\n  rofi_theme_parse_process_links_int(rofi_theme);\n}\n\nvoid rofi_theme_parse_process_conditionals(void) {\n  workarea mon;\n  monitor_active(&mon);\n  rofi_theme_parse_process_conditionals_int(mon, rofi_theme);\n}\n\nThemeMediaType rofi_theme_parse_media_type(const char *type) {\n  if (g_strcmp0(type, \"monitor-id\") == 0) {\n    return THEME_MEDIA_TYPE_MON_ID;\n  }\n  if (g_strcmp0(type, \"min-width\") == 0) {\n    return THEME_MEDIA_TYPE_MIN_WIDTH;\n  }\n  if (g_strcmp0(type, \"min-height\") == 0) {\n    return THEME_MEDIA_TYPE_MIN_HEIGHT;\n  }\n  if (g_strcmp0(type, \"max-width\") == 0) {\n    return THEME_MEDIA_TYPE_MAX_WIDTH;\n  }\n  if (g_strcmp0(type, \"max-height\") == 0) {\n    return THEME_MEDIA_TYPE_MAX_HEIGHT;\n  }\n  if (g_strcmp0(type, \"min-aspect-ratio\") == 0) {\n    return THEME_MEDIA_TYPE_MIN_ASPECT_RATIO;\n  }\n  if (g_strcmp0(type, \"max-aspect-ratio\") == 0) {\n    return THEME_MEDIA_TYPE_MAX_ASPECT_RATIO;\n  }\n  if (g_strcmp0(type, \"enabled\") == 0) {\n    return THEME_MEDIA_TYPE_BOOLEAN;\n  }\n  return THEME_MEDIA_TYPE_INVALID;\n}\n\nstatic gboolean rofi_theme_has_property_inside(Property *p,\n                                               const widget *wid_in,\n                                               const char *property) {\n  if (p) {\n    if (p->type == P_INHERIT) {\n      if (wid_in->parent) {\n        ThemeWidget *parent =\n            rofi_theme_find_widget(wid_in->parent->name, wid_in->state, FALSE);\n        Property *pp =\n            rofi_theme_find_property(parent, P_STRING, property, FALSE);\n        return rofi_theme_has_property_inside(pp, wid_in->parent, property);\n      }\n      return FALSE;\n    }\n    return TRUE;\n  }\n  return FALSE;\n}\ngboolean rofi_theme_has_property(const widget *wid_in, const PropertyType type,\n                                 const char *property) {\n  ThemeWidget *wid = rofi_theme_find_widget(wid_in->name, wid_in->state, FALSE);\n  Property *p = rofi_theme_find_property(wid, type, property, FALSE);\n  return rofi_theme_has_property_inside(p, wid_in, property);\n}\n\nvoid rofi_theme_set_disp_scale_func(disp_scale_func func) { disp_scale = func; }\n"
  },
  {
    "path": "source/timings.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** Log domain used by timings.*/\n#define G_LOG_DOMAIN \"Timings\"\n\n#include \"timings.h\"\n#include \"config.h\"\n#include \"rofi.h\"\n#include <stdio.h>\n/**\n * Timer used to calculate time stamps.\n */\nGTimer *global_timer = NULL;\n/**\n * Last timestamp made.\n */\ndouble global_timer_last = 0.0;\n\nvoid rofi_timings_init(void) {\n  global_timer = g_timer_new();\n  double now = g_timer_elapsed(global_timer, NULL);\n  g_debug(\"%4.6f (%2.6f): Started\", now, 0.0);\n}\n\nvoid rofi_timings_tick(const char *file, char const *str, int line,\n                       char const *msg) {\n  double now = g_timer_elapsed(global_timer, NULL);\n\n  g_debug(\"%4.6f (%2.6f): %s:%s:%-3d %s\", now, now - global_timer_last, file,\n          str, line, msg);\n  global_timer_last = now;\n}\n\nvoid rofi_timings_quit(void) {\n  double now = g_timer_elapsed(global_timer, NULL);\n  g_debug(\"%4.6f (%2.6f): Stopped\", now, 0.0);\n  g_timer_destroy(global_timer);\n}\n"
  },
  {
    "path": "source/view.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The Rofi View log domain */\n#define G_LOG_DOMAIN \"View\"\n\n#include <config.h>\n#include <locale.h>\n#include <signal.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include <glib.h>\n\n#include \"rofi.h\"\n\n#include \"settings.h\"\n#include \"timings.h\"\n\n#include \"display.h\"\n#include \"helper-theme.h\"\n#include \"helper.h\"\n#include \"mode.h\"\n\n#include \"view-internal.h\"\n#include \"view.h\"\n\n#include \"theme.h\"\n\n#ifdef ENABLE_XCB\n#include \"xcb-internal.h\"\n#include \"xcb.h\"\n#else\n#include \"xcb-dummy.h\"\n#endif\n\nstatic const view_proxy *proxy;\n\nvoid view_init(const view_proxy *view_in) { proxy = view_in; }\n\n/** Thread pool used for filtering */\nGThreadPool *tpool = NULL;\n\n/** Global pointer to the currently active RofiViewState */\nRofiViewState *current_active_menu = NULL;\n\nstruct _rofi_view_cache_state CacheState = {\n    .main_window = XCB_WINDOW_NONE,\n    .flags = MENU_NORMAL,\n    .views = G_QUEUE_INIT,\n    .refilter_timeout = 0,\n    .refilter_timeout_count = 0,\n    .max_refilter_time = 0.0,\n    .delayed_mode = FALSE,\n    .user_timeout = 0,\n    .overlay_timeout = 0,\n    .entry_history_enable = TRUE,\n    .entry_history = NULL,\n    .entry_history_length = 0,\n    .entry_history_index = 0,\n};\n\nstatic char *get_matching_state(RofiViewState *state) {\n  if (state->case_sensitive) {\n    if (config.sort) {\n      return \"±\";\n    } else {\n      return \"-\";\n    }\n  } else {\n    if (config.sort) {\n      return \"+\";\n    }\n  }\n  return \" \";\n}\n\n/**\n * Levenshtein Sorting.\n */\nstatic int lev_sort(const void *p1, const void *p2, void *arg) {\n  const int *a = p1;\n  const int *b = p2;\n  int *distances = arg;\n\n  return distances[*a] - distances[*b];\n}\n\nstatic void screenshot_taken_user_callback(const char *path) {\n  if (config.on_screenshot_taken == NULL)\n    return;\n\n  char **args = NULL;\n  int argv = 0;\n  helper_parse_setup(config.on_screenshot_taken, &args, &argv, \"{path}\", path,\n                     (char *)0);\n  if (args != NULL)\n    helper_execute(NULL, args, \"\", config.on_screenshot_taken, NULL);\n}\n\n/**\n * Stores a screenshot of Rofi at that point in time.\n */\nvoid rofi_capture_screenshot(void) {\n  RofiViewState *state = current_active_menu;\n  if (state == NULL || state->main_window == NULL) {\n    g_warning(\"Nothing to screenshot.\");\n    return;\n  }\n  const char *outp = g_getenv(\"ROFI_PNG_OUTPUT\");\n  const char *xdg_pict_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);\n  if (outp == NULL && xdg_pict_dir == NULL) {\n    g_warning(\"XDG user picture directory or ROFI_PNG_OUTPUT is not set. \"\n              \"Cannot store screenshot.\");\n    return;\n  }\n  // Get current time.\n  GDateTime *now = g_date_time_new_now_local();\n  // Format filename.\n  char *timestmp = g_date_time_format(now, \"rofi-%Y-%m-%d-%H%M\");\n  char *filename = g_strdup_printf(\"%s-%05d.png\", timestmp, 0);\n  // Build full path\n  char *fpath = NULL;\n  if (outp == NULL) {\n    int index = 0;\n    fpath = g_build_filename(xdg_pict_dir, filename, NULL);\n    while (g_file_test(fpath, G_FILE_TEST_EXISTS) && index < 99999) {\n      g_free(fpath);\n      g_free(filename);\n      // Try the next index.\n      index++;\n      // Format filename.\n      filename = g_strdup_printf(\"%s-%05d.png\", timestmp, index);\n      // Build full path\n      fpath = g_build_filename(xdg_pict_dir, filename, NULL);\n    }\n  } else {\n    fpath = g_strdup(outp);\n  }\n  fprintf(stderr, color_green \"Storing screenshot %s\\n\" color_reset, fpath);\n  cairo_surface_t *surf = cairo_image_surface_create(\n      CAIRO_FORMAT_ARGB32, state->width, state->height);\n  cairo_status_t status = cairo_surface_status(surf);\n  if (status != CAIRO_STATUS_SUCCESS) {\n    g_warning(\"Failed to produce screenshot '%s', got error: '%s'\", fpath,\n              cairo_status_to_string(status));\n  } else {\n    cairo_t *draw = cairo_create(surf);\n    status = cairo_status(draw);\n    if (status != CAIRO_STATUS_SUCCESS) {\n      g_warning(\"Failed to produce screenshot '%s', got error: '%s'\", fpath,\n                cairo_status_to_string(status));\n    } else {\n      widget_draw(WIDGET(state->main_window), draw);\n      status = cairo_surface_write_to_png(surf, fpath);\n      if (status != CAIRO_STATUS_SUCCESS) {\n        g_warning(\"Failed to produce screenshot '%s', got error: '%s'\", fpath,\n                  cairo_status_to_string(status));\n      }\n      screenshot_taken_user_callback(fpath);\n    }\n    cairo_destroy(draw);\n  }\n  // Cleanup\n  cairo_surface_destroy(surf);\n  g_free(fpath);\n  g_free(filename);\n  g_free(timestmp);\n  g_date_time_unref(now);\n}\n\nstatic void rofi_view_update_prompt(RofiViewState *state) {\n  if (state->prompt) {\n    const char *str = mode_get_display_name(state->sw);\n    textbox_text(state->prompt, str);\n  }\n}\n\nextern GList *list_of_warning_msgs;\nstatic void rofi_view_reload_message_bar(RofiViewState *state) {\n  if (state->mesg_box == NULL) {\n    return;\n  }\n  char *msg = mode_get_message(state->sw);\n  if (msg || list_of_warning_msgs) {\n    /** we want to popin warning here. */\n\n    GString *emesg = g_string_new(msg);\n    if (list_of_warning_msgs) {\n      if (msg) {\n        g_string_append_c(emesg, '\\n');\n      }\n      g_string_append(\n          emesg, \"The following warnings were detected when starting rofi:\\n\");\n      GList *iter = g_list_first(list_of_warning_msgs);\n      int index = 0;\n      for (; iter != NULL && index < 2; iter = g_list_next(iter)) {\n        GString *in_msg = (GString *)(iter->data);\n        g_string_append(emesg, \"\\n\\n\");\n        g_string_append(emesg, in_msg->str);\n        index++;\n      }\n      if (g_list_length(iter) > 1) {\n        g_string_append_printf(emesg, \"\\nThere are <b>%u</b> more errors.\",\n                               g_list_length(iter) - 1);\n      }\n    }\n    textbox_text(state->mesg_tb, emesg->str);\n    widget_enable(WIDGET(state->mesg_box));\n    g_string_free(emesg, TRUE);\n    g_free(msg);\n  } else {\n    widget_disable(WIDGET(state->mesg_box));\n  }\n}\n\nstatic void rofi_view_take_action(const char *name) {\n  ThemeWidget *wid = rofi_config_find_widget(name, NULL, TRUE);\n  if (wid) {\n    /** Check string property */\n    Property *p = rofi_theme_find_property(wid, P_STRING, \"action\", TRUE);\n    if (p != NULL && p->type == P_STRING) {\n      const char *action = p->value.s;\n      guint id = key_binding_get_action_from_name(action);\n      if (id != UINT32_MAX) {\n        rofi_view_trigger_action(rofi_view_get_active(), SCOPE_GLOBAL, id);\n      } else {\n        g_warning(\"Failed to parse keybinding: %s\\r\\n\", action);\n      }\n    }\n  }\n}\nstatic gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data) {\n  CacheState.user_timeout = 0;\n  rofi_view_take_action(\"timeout\");\n  return G_SOURCE_REMOVE;\n}\n\nstatic void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data) {\n  if (CacheState.user_timeout > 0) {\n    g_source_remove(CacheState.user_timeout);\n    CacheState.user_timeout = 0;\n  }\n  {\n    /** Find the widget */\n    ThemeWidget *wid = rofi_config_find_widget(\"timeout\", NULL, TRUE);\n    if (wid) {\n      /** Check string property */\n      Property *p = rofi_theme_find_property(wid, P_INTEGER, \"delay\", TRUE);\n      if (p != NULL && p->type == P_INTEGER && p->value.i > 0) {\n        int delay = p->value.i;\n        CacheState.user_timeout =\n            g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);\n      } else {\n        Property *prop = rofi_theme_find_property(wid, P_DOUBLE, \"delay\", TRUE);\n        if (prop != NULL && prop->type == P_DOUBLE && prop->value.f > 0.01) {\n          double delay = prop->value.f;\n          CacheState.user_timeout =\n              g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);\n        }\n      }\n    }\n  }\n}\n\nvoid rofi_view_restart(RofiViewState *state) {\n  state->quit = FALSE;\n  state->retv = MENU_CANCEL;\n}\n\nRofiViewState *rofi_view_get_active(void) { return current_active_menu; }\n\ntextbox *rofi_view_get_active_text(void) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state) {\n    return state->text;\n  }\n  return NULL;\n}\n\nvoid rofi_view_remove_active(RofiViewState *state) {\n  if (state == current_active_menu) {\n    rofi_view_set_active(NULL);\n  } else if (state) {\n    g_queue_remove(&(CacheState.views), state);\n  }\n}\nvoid rofi_view_set_active(RofiViewState *state) {\n  if (current_active_menu != NULL && state != NULL) {\n    g_queue_push_head(&(CacheState.views), current_active_menu);\n    // TODO check.\n    current_active_menu = state;\n    g_debug(\"stack view.\");\n    rofi_view_window_update_size(current_active_menu);\n    rofi_view_queue_redraw();\n    return;\n  } else if (state == NULL && !g_queue_is_empty(&(CacheState.views))) {\n    g_debug(\"pop view.\");\n    current_active_menu = g_queue_pop_head(&(CacheState.views));\n    rofi_view_window_update_size(current_active_menu);\n    rofi_view_queue_redraw();\n    return;\n  }\n  g_assert((current_active_menu == NULL && state != NULL) ||\n           (current_active_menu != NULL && state == NULL));\n  current_active_menu = state;\n  rofi_view_queue_redraw();\n}\n\nvoid rofi_view_set_selected_line(RofiViewState *state,\n                                 unsigned int selected_line) {\n  state->selected_line = selected_line;\n  // Find the line.\n  unsigned int selected = 0;\n  for (unsigned int i = 0; ((state->selected_line)) < UINT32_MAX && !selected &&\n                           i < state->filtered_lines;\n       i++) {\n    if (state->line_map[i] == (state->selected_line)) {\n      selected = i;\n      break;\n    }\n  }\n  listview_set_selected(state->list_view, selected);\n#ifdef ENABLE_XCB\n  if (config.backend == DISPLAY_XCB) {\n    // Clear the window and force an expose event resulting in a redraw.\n    xcb_clear_area(xcb->connection, 1, CacheState.main_window, 0, 0, 1, 1);\n    xcb_flush(xcb->connection);\n  }\n#endif\n}\n\nvoid rofi_view_free(RofiViewState *state) {\n  if (state->tokens) {\n    helper_tokenize_free(state->tokens);\n    state->tokens = NULL;\n  }\n  // Do this here?\n  // Wait for final release?\n  widget_free(WIDGET(state->main_window));\n\n  g_free(state->line_map);\n  g_free(state->distance);\n  // Free the switcher boxes.\n  // When state is free'ed we should no longer need these.\n  g_free(state->modes);\n  state->num_modes = 0;\n  g_free(state);\n}\n\nMenuReturn rofi_view_get_return_value(const RofiViewState *state) {\n  return state->retv;\n}\n\nunsigned int rofi_view_get_selected_line(const RofiViewState *state) {\n  return state->selected_line;\n}\n\nunsigned int rofi_view_get_next_position(const RofiViewState *state) {\n  unsigned int next_pos = state->selected_line;\n  unsigned int selected = listview_get_selected(state->list_view);\n  if ((selected + 1) < state->num_lines) {\n    (next_pos) = state->line_map[selected + 1];\n  }\n  return next_pos;\n}\n\nunsigned int rofi_view_get_completed(const RofiViewState *state) {\n  return state->quit;\n}\n\nconst char *rofi_view_get_user_input(const RofiViewState *state) {\n  if (state->text) {\n    return state->text->text;\n  }\n  return NULL;\n}\n\n/**\n * Create a new, 0 initialized RofiViewState structure.\n *\n * @returns a new 0 initialized RofiViewState\n */\nstatic RofiViewState *__rofi_view_state_create(void) {\n  return g_malloc0(sizeof(RofiViewState));\n}\n\n/**\n * Thread state for workers started for the view.\n */\ntypedef struct _thread_state_view {\n  /** Generic thread state. */\n  thread_state st;\n\n  /** Condition. */\n  GCond *cond;\n  /** Lock for condition. */\n  GMutex *mutex;\n  /** Count that is protected by lock. */\n  unsigned int *acount;\n\n  /** Current state. */\n  RofiViewState *state;\n  /** Start row for this worker. */\n  unsigned int start;\n  /** Stop row for this worker. */\n  unsigned int stop;\n  /** Rows processed. */\n  unsigned int count;\n\n  /** Pattern input to filter. */\n  const char *pattern;\n  /** Length of pattern. */\n  glong plen;\n} thread_state_view;\n/**\n * @param data A thread_state object.\n * @param user_data User data to pass to thread_state callback\n *\n * Small wrapper function that is internally used to pass a job to a worker.\n */\nstatic void rofi_view_call_thread(gpointer data, gpointer user_data) {\n  thread_state *t = (thread_state *)data;\n  t->callback(t, user_data);\n}\n\nstatic void filter_elements(thread_state *ts,\n                            G_GNUC_UNUSED gpointer user_data) {\n  thread_state_view *t = (thread_state_view *)ts;\n  for (unsigned int i = t->start; i < t->stop; i++) {\n    int match = mode_token_match(t->state->sw, t->state->tokens, i);\n    // If each token was matched, add it to list.\n    if (match) {\n      t->state->line_map[t->start + t->count] = i;\n      if (config.sort) {\n        // This is inefficient, need to fix it.\n        char *str = mode_get_completion(t->state->sw, i);\n        glong slen = g_utf8_strlen(str, -1);\n        switch (config.sorting_method_enum) {\n        case SORT_FZF:\n          t->state->distance[i] = rofi_scorer_fuzzy_evaluate(\n              t->pattern, t->plen, str, slen, t->state->case_sensitive);\n          break;\n        case SORT_NORMAL:\n        default:\n          t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen,\n                                              t->state->case_sensitive);\n          break;\n        }\n        g_free(str);\n      }\n      t->count++;\n    }\n  }\n  if (t->acount != NULL) {\n    g_mutex_lock(t->mutex);\n    (*(t->acount))--;\n    g_cond_signal(t->cond);\n    g_mutex_unlock(t->mutex);\n  }\n}\n\nvoid input_history_initialize(void) {\n  if (CacheState.entry_history_enable == FALSE) {\n    return;\n  }\n  CacheState.entry_history = NULL;\n  CacheState.entry_history_index = 0;\n  CacheState.entry_history_length = 0;\n\n  gchar *path = g_build_filename(cache_dir, \"rofi-entry-history.txt\", NULL);\n  if (g_file_test(path, G_FILE_TEST_EXISTS)) {\n    FILE *fp = fopen(path, \"r\");\n    if (fp) {\n      char *line = NULL;\n      size_t len = 0;\n      ssize_t nread;\n      while ((nread = getline(&line, &len, fp)) != -1) {\n        CacheState.entry_history = g_realloc(\n            CacheState.entry_history,\n            sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));\n        if (line[nread - 1] == '\\n') {\n          line[nread - 1] = '\\0';\n          nread--;\n        }\n        CacheState.entry_history[CacheState.entry_history_length].string =\n            g_strdup(line);\n        CacheState.entry_history[CacheState.entry_history_length].index =\n            strlen(line);\n        CacheState.entry_history_length++;\n        CacheState.entry_history_index++;\n      }\n      free(line);\n      fclose(fp);\n    }\n  }\n  g_free(path);\n  CacheState.entry_history = g_realloc(\n      CacheState.entry_history,\n      sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));\n  CacheState.entry_history[CacheState.entry_history_length].string =\n      g_strdup(\"\");\n  CacheState.entry_history[CacheState.entry_history_length].index = 0;\n  CacheState.entry_history_length++;\n}\nvoid input_history_save(void) {\n  if (CacheState.entry_history_enable == FALSE) {\n    return;\n  }\n  if (CacheState.entry_history_length > 0) {\n    // History max.\n    int max_history = 20;\n    ThemeWidget *wid = rofi_config_find_widget(\"entry\", NULL, TRUE);\n    if (wid) {\n      Property *p =\n          rofi_theme_find_property(wid, P_INTEGER, \"max-history\", TRUE);\n      if (p != NULL && p->type == P_INTEGER) {\n        max_history = p->value.i;\n      }\n    }\n    gchar *path = g_build_filename(cache_dir, \"rofi-entry-history.txt\", NULL);\n    g_debug(\"Entry filename output: '%s'\", path);\n    FILE *fp = fopen(path, \"w\");\n    if (fp) {\n      gssize start = MAX(0, (CacheState.entry_history_length - max_history));\n      for (gssize i = start; i < CacheState.entry_history_length; i++) {\n        if (strlen(CacheState.entry_history[i].string) > 0) {\n          fprintf(fp, \"%s\\n\", CacheState.entry_history[i].string);\n        }\n      }\n      fclose(fp);\n    }\n    g_free(path);\n  }\n  // Cleanups.\n  if (CacheState.entry_history != NULL) {\n    for (ssize_t i = 0; i < CacheState.entry_history_length; i++) {\n      g_free(CacheState.entry_history[i].string);\n    }\n    g_free(CacheState.entry_history);\n    CacheState.entry_history = NULL;\n    CacheState.entry_history_length = 0;\n    CacheState.entry_history_index = 0;\n  }\n}\n\n/**\n * Nav helper functions, to avoid duplicate code.\n */\n\n/**\n * @param state The current RofiViewState\n *\n * Tab handling.\n */\nstatic void rofi_view_nav_row_tab(RofiViewState *state) {\n  if (state->filtered_lines == 1) {\n    state->retv = MENU_OK;\n    (state->selected_line) =\n        state->line_map[listview_get_selected(state->list_view)];\n    state->quit = 1;\n    return;\n  }\n\n  // Double tab!\n  if (state->filtered_lines == 0 && ROW_TAB == state->prev_action) {\n    state->retv = MENU_NEXT;\n    (state->selected_line) = 0;\n    state->quit = TRUE;\n  } else {\n    listview_nav_down(state->list_view);\n  }\n  state->prev_action = ROW_TAB;\n}\n/**\n * @param state The current RofiViewState\n *\n * complete current row.\n */\ninline static void rofi_view_nav_row_select(RofiViewState *state) {\n  if (state->list_view == NULL) {\n    return;\n  }\n  unsigned int selected = listview_get_selected(state->list_view);\n  // If a valid item is selected, return that..\n  if (selected < state->filtered_lines) {\n    char *str = mode_get_completion(state->sw, state->line_map[selected]);\n    textbox_text(state->text, str);\n    g_free(str);\n    textbox_keybinding(state->text, MOVE_END);\n    state->refilter = TRUE;\n  }\n}\n\n/**\n * @param state The current RofiViewState\n *\n * Move the selection to first row.\n */\ninline static void rofi_view_nav_first(RofiViewState *state) {\n  //    state->selected = 0;\n  listview_set_selected(state->list_view, 0);\n}\n\n/**\n * @param state The current RofiViewState\n *\n * Move the selection to last row.\n */\ninline static void rofi_view_nav_last(RofiViewState *state) {\n  // If no lines, do nothing.\n  if (state->filtered_lines == 0) {\n    return;\n  }\n  // state->selected = state->filtered_lines - 1;\n  listview_set_selected(state->list_view, -1);\n}\nstatic void selection_changed_user_callback(unsigned int index,\n                                            RofiViewState *state) {\n  if (config.on_selection_changed == NULL)\n    return;\n\n  int fstate = 0;\n  char *text = mode_get_display_value(state->sw, state->line_map[index],\n                                      &fstate, NULL, TRUE);\n  char **args = NULL;\n  int argv = 0;\n  helper_parse_setup(config.on_selection_changed, &args, &argv, \"{entry}\", text,\n                     (char *)0);\n  if (args != NULL)\n    helper_execute(NULL, args, \"\", config.on_selection_changed, NULL);\n  g_free(text);\n}\nstatic void selection_changed_callback(G_GNUC_UNUSED listview *lv,\n                                       unsigned int index, void *udata) {\n  RofiViewState *state = (RofiViewState *)udata;\n  if (index < state->filtered_lines) {\n    if (state->previous_line != state->line_map[index]) {\n      selection_changed_user_callback(index, state);\n      state->previous_line = state->line_map[index];\n    }\n  }\n  if (state->tb_current_entry) {\n    if (index < state->filtered_lines) {\n      int fstate = 0;\n      char *text = mode_get_display_value(state->sw, state->line_map[index],\n                                          &fstate, NULL, TRUE);\n      textbox_text(state->tb_current_entry, text);\n      g_free(text);\n    } else {\n      textbox_text(state->tb_current_entry, \"\");\n    }\n  }\n  if (state->icon_current_entry) {\n    if (index < state->filtered_lines) {\n      int icon_height =\n          widget_get_desired_height(WIDGET(state->icon_current_entry),\n                                    WIDGET(state->icon_current_entry)->w);\n      cairo_surface_t *surf_icon =\n          mode_get_icon(state->sw, state->line_map[index], icon_height);\n      icon_set_surface(state->icon_current_entry, surf_icon);\n    } else {\n      icon_set_surface(state->icon_current_entry, NULL);\n    }\n  }\n}\nstatic void update_callback(textbox *t, icon *ico, unsigned int index,\n                            void *udata, TextBoxFontType *type, gboolean full) {\n  RofiViewState *state = (RofiViewState *)udata;\n  if (full) {\n    GList *add_list = NULL;\n    int fstate = 0;\n    char *text = mode_get_display_value(state->sw, state->line_map[index],\n                                        &fstate, &add_list, TRUE);\n    (*type) |= fstate;\n\n    if (ico) {\n      int icon_height = widget_get_desired_height(WIDGET(ico), WIDGET(ico)->w);\n      cairo_surface_t *surf_icon =\n          mode_get_icon(state->sw, state->line_map[index], icon_height);\n      icon_set_surface(ico, surf_icon);\n    }\n    if (t) {\n      // TODO needed for markup.\n      textbox_font(t, *type);\n      // Move into list view.\n      textbox_text(t, text);\n      PangoAttrList *list = textbox_get_pango_attributes(t);\n      if (list != NULL) {\n        pango_attr_list_ref(list);\n      } else {\n        list = pango_attr_list_new();\n      }\n\n      if (state->tokens) {\n        RofiHighlightColorStyle th = {ROFI_HL_BOLD | ROFI_HL_UNDERLINE,\n                                      {0.0, 0.0, 0.0, 0.0}};\n        th = rofi_theme_get_highlight(WIDGET(t), \"highlight\", th);\n        helper_token_match_get_pango_attr(th, state->tokens,\n                                          textbox_get_visible_text(t), list);\n      }\n      for (GList *iter = g_list_first(add_list); iter != NULL;\n           iter = g_list_next(iter)) {\n        pango_attr_list_insert(list, (PangoAttribute *)(iter->data));\n      }\n      textbox_set_pango_attributes(t, list);\n      pango_attr_list_unref(list);\n    }\n\n    g_list_free(add_list);\n    g_free(text);\n  } else {\n    // Never called.\n    int fstate = 0;\n    mode_get_display_value(state->sw, state->line_map[index], &fstate, NULL,\n                           FALSE);\n    (*type) |= fstate;\n    // TODO needed for markup.\n    textbox_font(t, *type);\n  }\n}\nstatic void page_changed_callback(void) {\n  rofi_view_workers_finalize();\n  rofi_view_workers_initialize();\n}\n\nstatic void _rofi_view_reload_row(RofiViewState *state) {\n  g_free(state->line_map);\n  g_free(state->distance);\n  state->num_lines = mode_get_num_entries(state->sw);\n  state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));\n  state->distance = g_malloc0_n(state->num_lines, sizeof(int));\n  listview_set_max_lines(state->list_view, state->num_lines);\n  rofi_view_reload_message_bar(state);\n}\n\nstatic gboolean rofi_view_refilter_real(RofiViewState *state) {\n  CacheState.refilter_timeout = 0;\n  CacheState.refilter_timeout_count = 0;\n  if (state->sw == NULL) {\n    return G_SOURCE_REMOVE;\n  }\n  GTimer *timer = g_timer_new();\n  TICK_N(\"Filter start\");\n  if (state->reload) {\n    _rofi_view_reload_row(state);\n    state->reload = FALSE;\n  }\n  TICK_N(\"Filter reload rows\");\n  if (state->tokens) {\n    helper_tokenize_free(state->tokens);\n    state->tokens = NULL;\n  }\n  TICK_N(\"Filter tokenize\");\n  if (state->text && strlen(state->text->text) > 0) {\n\n    listview_set_filtered(state->list_view, TRUE);\n    unsigned int j = 0;\n    gchar *pattern = mode_preprocess_input(state->sw, state->text->text);\n    glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;\n    state->case_sensitive = parse_case_sensitivity(state->text->text);\n    state->tokens = helper_tokenize(pattern, state->case_sensitive);\n\n    if (config.case_smart && state->case_indicator) {\n      textbox_text(state->case_indicator, get_matching_state(state));\n    }\n    /**\n     * On long lists it can be beneficial to parallelize.\n     * If number of threads is 1, no thread is spawn.\n     * If number of threads > 1 and there are enough (> 1000) items, spawn jobs\n     * for the thread pool. For large lists with 8 threads I see a factor three\n     * speedup of the whole function.\n     */\n    unsigned int nt = MAX(1, state->num_lines / 500);\n    // Limit the number of jobs, it could cause stack overflow if we don´t\n    // limit.\n    nt = MIN(nt, config.threads * 4);\n    thread_state_view states[nt];\n    GCond cond;\n    GMutex mutex;\n    g_mutex_init(&mutex);\n    g_cond_init(&cond);\n    unsigned int count = nt;\n    unsigned int steps = (state->num_lines + nt) / nt;\n    for (unsigned int i = 0; i < nt; i++) {\n      states[i].state = state;\n      states[i].start = i * steps;\n      states[i].stop = MIN(state->num_lines, (i + 1) * steps);\n      states[i].count = 0;\n      states[i].cond = &cond;\n      states[i].mutex = &mutex;\n      states[i].acount = &count;\n      states[i].plen = plen;\n      states[i].pattern = pattern;\n      states[i].st.callback = filter_elements;\n      states[i].st.free = NULL;\n      states[i].st.priority = G_PRIORITY_HIGH;\n      if (i > 0) {\n        g_thread_pool_push(tpool, &states[i], NULL);\n      }\n    }\n    // Run one in this thread.\n    rofi_view_call_thread(&states[0], NULL);\n    // No need to do this with only one thread.\n    if (nt > 1) {\n      g_mutex_lock(&mutex);\n      while (count > 0) {\n        g_cond_wait(&cond, &mutex);\n      }\n      g_mutex_unlock(&mutex);\n    }\n    g_cond_clear(&cond);\n    g_mutex_clear(&mutex);\n    for (unsigned int i = 0; i < nt; i++) {\n      if (j != states[i].start) {\n        memmove(&(state->line_map[j]), &(state->line_map[states[i].start]),\n                sizeof(unsigned int) * (states[i].count));\n      }\n      j += states[i].count;\n    }\n    if (config.sort) {\n      g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,\n                        state->distance);\n    }\n\n    // Cleanup + bookkeeping.\n    state->filtered_lines = j;\n    g_free(pattern);\n\n    double elapsed = g_timer_elapsed(timer, NULL);\n\n    CacheState.max_refilter_time = elapsed;\n  } else {\n    listview_set_filtered(state->list_view, FALSE);\n    for (unsigned int i = 0; i < state->num_lines; i++) {\n      state->line_map[i] = i;\n    }\n    state->filtered_lines = state->num_lines;\n  }\n  TICK_N(\"Filter matching done\");\n  listview_set_num_elements(state->list_view, state->filtered_lines);\n\n  if (state->tb_filtered_rows) {\n    char *r = g_strdup_printf(\"%u\", state->filtered_lines);\n    textbox_text(state->tb_filtered_rows, r);\n    g_free(r);\n  }\n  if (state->tb_total_rows) {\n    char *r = g_strdup_printf(\"%u\", state->num_lines);\n    textbox_text(state->tb_total_rows, r);\n    g_free(r);\n  }\n  TICK_N(\"Update filter lines\");\n\n  if (config.auto_select == TRUE && state->filtered_lines == 1 &&\n      state->num_lines > 1) {\n    (state->selected_line) =\n        state->line_map[listview_get_selected(state->list_view)];\n    state->retv = MENU_OK;\n    state->quit = TRUE;\n  }\n\n  // Size the window.\n  int height = rofi_view_calculate_window_height(state);\n  if (height != state->height) {\n    state->height = height;\n    rofi_view_calculate_window_position(state);\n    rofi_view_window_update_size(state);\n    g_debug(\"Resize based on re-filter\");\n  }\n  TICK_N(\"Filter resize window based on window \");\n  state->refilter = FALSE;\n  TICK_N(\"Filter done\");\n  rofi_view_update(state, TRUE);\n\n  g_timer_destroy(timer);\n  return G_SOURCE_REMOVE;\n}\nvoid rofi_view_refilter(RofiViewState *state) {\n  CacheState.refilter_timeout_count++;\n  if (CacheState.refilter_timeout != 0) {\n\n    g_source_remove(CacheState.refilter_timeout);\n    CacheState.refilter_timeout = 0;\n  }\n  if (CacheState.max_refilter_time > (config.refilter_timeout_limit / 1000.0) &&\n      state->text && strlen(state->text->text) > 0 &&\n      CacheState.refilter_timeout_count < 25) {\n    if (CacheState.delayed_mode == FALSE) {\n      g_warning(\n          \"Filtering took %f seconds ( %f ), switching to delayed filter\\n\",\n          CacheState.max_refilter_time, config.refilter_timeout_limit / 1000.0);\n      CacheState.delayed_mode = TRUE;\n    }\n    CacheState.refilter_timeout =\n        g_timeout_add(200, (GSourceFunc)rofi_view_refilter_real, state);\n  } else {\n    if (CacheState.delayed_mode == TRUE && state->text &&\n        strlen(state->text->text) > 0 &&\n        CacheState.refilter_timeout_count < 25) {\n      g_warning(\n          \"Filtering took %f seconds , switching back to instant filter\\n\",\n          CacheState.max_refilter_time);\n      CacheState.delayed_mode = FALSE;\n    }\n    rofi_view_refilter_real(state);\n  }\n}\nstatic void rofi_view_refilter_force(RofiViewState *state) {\n  if (CacheState.refilter_timeout != 0) {\n    g_source_remove(CacheState.refilter_timeout);\n    CacheState.refilter_timeout = 0;\n  }\n  if (state->refilter) {\n    rofi_view_refilter_real(state);\n  }\n}\n/**\n * @param state The Menu Handle\n *\n * Check if a finalize function is set, and if sets executes it.\n */\nvoid process_result(RofiViewState *state);\nvoid rofi_view_finalize(RofiViewState *state) {\n  if (state && state->finalize != NULL) {\n    state->finalize(state);\n  }\n}\n\n/**\n * This function should be called when the input of the entry is changed.\n * TODO: Evaluate if this needs to be a 'signal' on textbox?\n */\nstatic void rofi_view_input_changed(void) {\n  rofi_view_take_action(\"inputchange\");\n\n  RofiViewState *state = current_active_menu;\n  if (CacheState.entry_history_enable && state) {\n    if (CacheState.entry_history[CacheState.entry_history_index].string !=\n        NULL) {\n      g_free(CacheState.entry_history[CacheState.entry_history_index].string);\n    }\n    CacheState.entry_history[CacheState.entry_history_index].string =\n        textbox_get_text(state->text);\n    CacheState.entry_history[CacheState.entry_history_index].index =\n        textbox_get_cursor(state->text);\n  }\n}\n\n#ifdef ENABLE_WAYLAND\nstatic void rofi_view_clipboard_callback(char *clipboard_data,\n                                         G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (clipboard_data != NULL) {\n    if (state != NULL) {\n      rofi_view_handle_text(state, clipboard_data);\n    }\n    g_free(clipboard_data);\n  }\n}\n#endif\n\nstatic void rofi_view_trigger_global_action(KeyBindingAction action) {\n  RofiViewState *state = rofi_view_get_active();\n  switch (action) {\n  // Handling of paste\n  case PASTE_PRIMARY:\n#ifdef ENABLE_XCB\n    if (config.backend == DISPLAY_XCB) {\n      xcb_convert_selection(xcb->connection, CacheState.main_window,\n                            XCB_ATOM_PRIMARY, xcb->ewmh.UTF8_STRING,\n                            xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);\n      xcb_flush(xcb->connection);\n    }\n#endif\n#ifdef ENABLE_WAYLAND\n    if (config.backend == DISPLAY_WAYLAND) {\n      display_get_clipboard_data(CLIPBOARD_PRIMARY,\n                                 rofi_view_clipboard_callback, NULL);\n    }\n#endif\n    break;\n  case PASTE_SECONDARY:\n#ifdef ENABLE_XCB\n    if (config.backend == DISPLAY_XCB) {\n      xcb_convert_selection(xcb->connection, CacheState.main_window,\n                            netatoms[CLIPBOARD], xcb->ewmh.UTF8_STRING,\n                            xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);\n      xcb_flush(xcb->connection);\n    }\n#endif\n#ifdef ENABLE_WAYLAND\n    if (config.backend == DISPLAY_WAYLAND) {\n      display_get_clipboard_data(CLIPBOARD_DEFAULT,\n                                 rofi_view_clipboard_callback, NULL);\n    }\n#endif\n    break;\n  case COPY_SECONDARY: {\n    char *data = NULL;\n    unsigned int selected = listview_get_selected(state->list_view);\n    if (selected < state->filtered_lines) {\n      data = mode_get_completion(state->sw, state->line_map[selected]);\n    } else if (state->text && state->text->text) {\n      data = g_strdup(state->text->text);\n    }\n    if (data) {\n#ifdef ENABLE_XCB\n      if (config.backend == DISPLAY_XCB) {\n        xcb_stuff_set_clipboard(data);\n        xcb_set_selection_owner(xcb->connection, CacheState.main_window,\n                                netatoms[CLIPBOARD], XCB_CURRENT_TIME);\n        xcb_flush(xcb->connection);\n      }\n#endif\n#ifdef ENABLE_WAYLAND\n      if (config.backend == DISPLAY_WAYLAND) {\n        // TODO\n      }\n#endif\n    }\n  } break;\n  case SCREENSHOT:\n    rofi_capture_screenshot();\n    break;\n  case CHANGE_ELLIPSIZE:\n    if (state->list_view) {\n      listview_toggle_ellipsizing(state->list_view);\n    }\n    break;\n  case TOGGLE_SORT:\n    if (state->case_indicator != NULL) {\n      config.sort = !config.sort;\n      state->refilter = TRUE;\n      textbox_text(state->case_indicator, get_matching_state(state));\n    }\n    break;\n  case MODE_PREVIOUS:\n    state->retv = MENU_PREVIOUS;\n    (state->selected_line) = 0;\n    state->quit = TRUE;\n    break;\n  // Menu navigation.\n  case MODE_NEXT:\n    state->retv = MENU_NEXT;\n    (state->selected_line) = 0;\n    state->quit = TRUE;\n    break;\n  case MODE_COMPLETE: {\n    unsigned int selected = listview_get_selected(state->list_view);\n    state->selected_line = UINT32_MAX;\n    if (selected < state->filtered_lines) {\n      state->selected_line = state->line_map[selected];\n    }\n    state->retv = MENU_COMPLETE;\n    state->quit = TRUE;\n    break;\n  }\n  // Toggle case sensitivity.\n  case TOGGLE_CASE_SENSITIVITY:\n    if (state->case_indicator != NULL) {\n      config.case_sensitive = !config.case_sensitive;\n      (state->selected_line) = 0;\n      state->refilter = TRUE;\n      textbox_text(state->case_indicator, get_matching_state(state));\n    }\n    break;\n  // Special delete entry command.\n  case DELETE_ENTRY: {\n    unsigned int selected = listview_get_selected(state->list_view);\n    if (selected < state->filtered_lines) {\n      (state->selected_line) = state->line_map[selected];\n      state->retv = MENU_ENTRY_DELETE;\n      state->quit = TRUE;\n    }\n    break;\n  }\n  case SELECT_ELEMENT_1:\n  case SELECT_ELEMENT_2:\n  case SELECT_ELEMENT_3:\n  case SELECT_ELEMENT_4:\n  case SELECT_ELEMENT_5:\n  case SELECT_ELEMENT_6:\n  case SELECT_ELEMENT_7:\n  case SELECT_ELEMENT_8:\n  case SELECT_ELEMENT_9:\n  case SELECT_ELEMENT_10: {\n    unsigned int index = action - SELECT_ELEMENT_1;\n    if (index < state->filtered_lines) {\n      state->selected_line = state->line_map[index];\n      state->retv = MENU_OK;\n      state->quit = TRUE;\n    }\n    break;\n  }\n  case CUSTOM_1:\n  case CUSTOM_2:\n  case CUSTOM_3:\n  case CUSTOM_4:\n  case CUSTOM_5:\n  case CUSTOM_6:\n  case CUSTOM_7:\n  case CUSTOM_8:\n  case CUSTOM_9:\n  case CUSTOM_10:\n  case CUSTOM_11:\n  case CUSTOM_12:\n  case CUSTOM_13:\n  case CUSTOM_14:\n  case CUSTOM_15:\n  case CUSTOM_16:\n  case CUSTOM_17:\n  case CUSTOM_18:\n  case CUSTOM_19: {\n    state->selected_line = UINT32_MAX;\n    unsigned int selected = listview_get_selected(state->list_view);\n    if (selected < state->filtered_lines) {\n      (state->selected_line) = state->line_map[selected];\n    }\n    state->retv = MENU_CUSTOM_COMMAND | ((action - CUSTOM_1) & MENU_LOWER_MASK);\n    state->quit = TRUE;\n    break;\n  }\n  // If you add a binding here, make sure to add it to\n  // rofi_view_keyboard_navigation too\n  case CANCEL:\n    state->retv = MENU_CANCEL;\n    state->quit = TRUE;\n    break;\n  case ELEMENT_NEXT:\n    listview_nav_next(state->list_view);\n    break;\n  case ELEMENT_PREV:\n    listview_nav_prev(state->list_view);\n    break;\n  case ROW_UP:\n    listview_nav_up(state->list_view);\n    break;\n  case ROW_TAB:\n    rofi_view_nav_row_tab(state);\n    break;\n  case ROW_DOWN:\n    listview_nav_down(state->list_view);\n    break;\n  case ROW_LEFT:\n    listview_nav_left(state->list_view);\n    break;\n  case ROW_RIGHT:\n    listview_nav_right(state->list_view);\n    break;\n  case PAGE_PREV:\n    listview_nav_page_prev(state->list_view);\n    break;\n  case PAGE_NEXT:\n    listview_nav_page_next(state->list_view);\n    break;\n  case ROW_FIRST:\n    rofi_view_nav_first(state);\n    break;\n  case ROW_LAST:\n    rofi_view_nav_last(state);\n    break;\n  case ROW_SELECT:\n    rofi_view_nav_row_select(state);\n    break;\n  // If you add a binding here, make sure to add it to textbox_keybinding too\n  case MOVE_CHAR_BACK: {\n    if (textbox_keybinding(state->text, action) == 0) {\n      listview_nav_left(state->list_view);\n    }\n    break;\n  }\n  case MOVE_CHAR_FORWARD: {\n    if (textbox_keybinding(state->text, action) == 0) {\n      listview_nav_right(state->list_view);\n    }\n    break;\n  }\n  case CLEAR_LINE:\n  case MOVE_FRONT:\n  case MOVE_END:\n  case REMOVE_TO_EOL:\n  case REMOVE_TO_SOL:\n  case TRANSPOSE_CHARS:\n  case REMOVE_WORD_BACK:\n  case REMOVE_WORD_FORWARD:\n  case REMOVE_CHAR_FORWARD:\n  case MOVE_WORD_BACK:\n  case MOVE_WORD_FORWARD:\n  case REMOVE_CHAR_BACK: {\n    int rc = textbox_keybinding(state->text, action);\n    if (rc == 1) {\n      // Entry changed.\n      state->refilter = TRUE;\n      rofi_view_input_changed();\n    } else if (rc == 2) {\n      // Movement.\n    }\n    break;\n  }\n  case ACCEPT_ALT: {\n    rofi_view_refilter_force(state);\n    unsigned int selected = listview_get_selected(state->list_view);\n    state->selected_line = UINT32_MAX;\n    if (selected < state->filtered_lines) {\n      (state->selected_line) = state->line_map[selected];\n      state->retv = MENU_OK;\n    } else {\n      // Nothing entered and nothing selected.\n      state->retv = MENU_CUSTOM_INPUT;\n    }\n    state->retv |= MENU_CUSTOM_ACTION;\n    state->quit = TRUE;\n    break;\n  }\n  case ACCEPT_CUSTOM: {\n    rofi_view_refilter_force(state);\n    state->selected_line = UINT32_MAX;\n    state->retv = MENU_CUSTOM_INPUT;\n    state->quit = TRUE;\n    break;\n  }\n  case ACCEPT_CUSTOM_ALT: {\n    rofi_view_refilter_force(state);\n    state->selected_line = UINT32_MAX;\n    state->retv = MENU_CUSTOM_INPUT | MENU_CUSTOM_ACTION;\n    state->quit = TRUE;\n    break;\n  }\n  case ACCEPT_ENTRY: {\n    rofi_view_refilter_force(state);\n    // If a valid item is selected, return that..\n    unsigned int selected = listview_get_selected(state->list_view);\n    state->selected_line = UINT32_MAX;\n    if (selected < state->filtered_lines) {\n      (state->selected_line) = state->line_map[selected];\n      state->retv = MENU_OK;\n    } else {\n      // Nothing entered and nothing selected.\n      state->retv = MENU_CUSTOM_INPUT;\n    }\n    state->quit = TRUE;\n    break;\n  }\n  case ENTRY_HISTORY_DOWN: {\n    if (CacheState.entry_history_enable && state->text) {\n      CacheState.entry_history[CacheState.entry_history_index].index =\n          textbox_get_cursor(state->text);\n      if (CacheState.entry_history_index > 0) {\n        CacheState.entry_history_index--;\n      }\n      if (state->text) {\n        textbox_text(\n            state->text,\n            CacheState.entry_history[CacheState.entry_history_index].string);\n        textbox_cursor(\n            state->text,\n            CacheState.entry_history[CacheState.entry_history_index].index);\n        state->refilter = TRUE;\n      }\n    }\n    break;\n  }\n  case ENTRY_HISTORY_UP: {\n    if (CacheState.entry_history_enable && state->text) {\n      if (CacheState.entry_history[CacheState.entry_history_index].string !=\n          NULL) {\n        g_free(CacheState.entry_history[CacheState.entry_history_index].string);\n      }\n      CacheState.entry_history[CacheState.entry_history_index].string =\n          textbox_get_text(state->text);\n      CacheState.entry_history[CacheState.entry_history_index].index =\n          textbox_get_cursor(state->text);\n      // Don't create up if current is empty.\n      if (strlen(\n              CacheState.entry_history[CacheState.entry_history_index].string) >\n          0) {\n        CacheState.entry_history_index++;\n        if (CacheState.entry_history_index >= CacheState.entry_history_length) {\n          CacheState.entry_history =\n              g_realloc(CacheState.entry_history,\n                        sizeof(EntryHistoryIndex) *\n                            (CacheState.entry_history_length + 1));\n          CacheState.entry_history[CacheState.entry_history_length].string =\n              g_strdup(\"\");\n          CacheState.entry_history[CacheState.entry_history_length].index = 0;\n          CacheState.entry_history_length++;\n        }\n      }\n      textbox_text(\n          state->text,\n          CacheState.entry_history[CacheState.entry_history_index].string);\n      textbox_cursor(\n          state->text,\n          CacheState.entry_history[CacheState.entry_history_index].index);\n      state->refilter = TRUE;\n    }\n    break;\n  }\n  case MATCHER_UP:\n    helper_select_next_matching_mode();\n    rofi_view_refilter(state);\n    rofi_view_set_overlay_timeout(state, helper_get_matching_mode_str());\n    break;\n  case MATCHER_DOWN:\n    helper_select_previous_matching_mode();\n    rofi_view_refilter(state);\n    rofi_view_set_overlay_timeout(state, helper_get_matching_mode_str());\n    break;\n  }\n}\n\ngboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope,\n                                guint action) {\n  switch (scope) {\n  case SCOPE_GLOBAL:\n    return TRUE;\n  case SCOPE_MOUSE_LISTVIEW:\n  case SCOPE_MOUSE_LISTVIEW_ELEMENT:\n  case SCOPE_MOUSE_EDITBOX:\n  case SCOPE_MOUSE_SCROLLBAR:\n  case SCOPE_MOUSE_MODE_SWITCHER: {\n    gint x = state->mouse.x, y = state->mouse.y;\n    widget *target = widget_find_mouse_target(WIDGET(state->main_window),\n                                              (WidgetType)scope, x, y);\n    if (target == NULL) {\n      return FALSE;\n    }\n    widget_xy_to_relative(target, &x, &y);\n    switch (widget_check_action(target, action, x, y)) {\n    case WIDGET_TRIGGER_ACTION_RESULT_IGNORED:\n      return FALSE;\n    case WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END:\n    case WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN:\n    case WIDGET_TRIGGER_ACTION_RESULT_HANDLED:\n      return TRUE;\n    }\n    break;\n  }\n  }\n  return FALSE;\n}\n\nvoid rofi_view_trigger_action(RofiViewState *state, BindingsScope scope,\n                              guint action) {\n  rofi_view_set_user_timeout(NULL);\n  switch (scope) {\n  case SCOPE_GLOBAL:\n    rofi_view_trigger_global_action(action);\n    return;\n  case SCOPE_MOUSE_LISTVIEW:\n  case SCOPE_MOUSE_LISTVIEW_ELEMENT:\n  case SCOPE_MOUSE_EDITBOX:\n  case SCOPE_MOUSE_SCROLLBAR:\n  case SCOPE_MOUSE_MODE_SWITCHER: {\n    gint x = state->mouse.x, y = state->mouse.y;\n    // If we already captured a motion, always forward action to this widget.\n    widget *target = state->mouse.motion_target;\n    // If we have not a previous captured motion, lookup widget.\n    if (target == NULL) {\n      target = widget_find_mouse_target(WIDGET(state->main_window),\n                                        (WidgetType)scope, x, y);\n    }\n    if (target == NULL) {\n      return;\n    }\n    widget_xy_to_relative(target, &x, &y);\n    switch (widget_trigger_action(target, action, x, y)) {\n    case WIDGET_TRIGGER_ACTION_RESULT_IGNORED:\n      return;\n    case WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END:\n      target = NULL;\n      rofi_fallthrough;\n    case WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN:\n      state->mouse.motion_target = target;\n      rofi_fallthrough;\n    case WIDGET_TRIGGER_ACTION_RESULT_HANDLED:\n      return;\n    }\n    break;\n  }\n  }\n}\n\nvoid rofi_view_handle_text(RofiViewState *state, const char *text) {\n  if (state == NULL || state->text == NULL) {\n    return;\n  }\n  if (textbox_append_text(state->text, text, strlen(text))) {\n    state->refilter = TRUE;\n    rofi_view_input_changed();\n  }\n}\n\n#if 0\nstatic X11CursorType rofi_cursor_type_to_x11_cursor_type ( RofiCursorType type )\n{\n    switch ( type )\n    {\n    case ROFI_CURSOR_DEFAULT:\n        return CURSOR_DEFAULT;\n\n    case ROFI_CURSOR_POINTER:\n        return CURSOR_POINTER;\n\n    case ROFI_CURSOR_TEXT:\n        return CURSOR_TEXT;\n    }\n\n    return CURSOR_DEFAULT;\n}\n#endif\n\nstatic RofiCursorType rofi_view_resolve_cursor(RofiViewState *state, gint x,\n                                               gint y) {\n  widget *target = widget_find_mouse_target(WIDGET(state->main_window),\n                                            WIDGET_TYPE_UNKNOWN, x, y);\n\n  return target != NULL ? target->cursor_type : ROFI_CURSOR_DEFAULT;\n}\n\nvoid rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y,\n                                   gboolean find_mouse_target) {\n  state->mouse.x = x;\n  state->mouse.y = y;\n\n  RofiCursorType cursor_type = rofi_view_resolve_cursor(state, x, y);\n\n  rofi_view_set_cursor(cursor_type);\n\n  if (find_mouse_target) {\n    widget *target = widget_find_mouse_target(\n        WIDGET(state->main_window), WIDGET_TYPE_LISTVIEW_ELEMENT, x, y);\n\n    if (target != NULL) {\n      state->mouse.motion_target = target;\n    }\n  }\n\n  if (state->mouse.motion_target != NULL) {\n    widget_xy_to_relative(state->mouse.motion_target, &x, &y);\n    widget_motion_notify(state->mouse.motion_target, x, y);\n\n    if (find_mouse_target) {\n      state->mouse.motion_target = NULL;\n    }\n  }\n}\n\nstatic void rofi_quit_user_callback(RofiViewState *state) {\n  if (state->retv & MENU_OK) {\n    if (config.on_entry_accepted == NULL)\n      return;\n    int fstate = 0;\n    unsigned int selected = listview_get_selected(state->list_view);\n    // TODO: handle custom text\n    if (selected >= state->filtered_lines)\n      return;\n    // Pass selected text to custom command\n    char *text = mode_get_display_value(state->sw, state->line_map[selected],\n                                        &fstate, NULL, TRUE);\n    char **args = NULL;\n    int argv = 0;\n    helper_parse_setup(config.on_entry_accepted, &args, &argv, \"{entry}\", text,\n                       (char *)0);\n    if (args != NULL)\n      helper_execute(NULL, args, \"\", config.on_entry_accepted, NULL);\n    g_free(text);\n  } else if (state->retv & MENU_CANCEL) {\n    if (config.on_menu_canceled == NULL)\n      return;\n    helper_execute_command(NULL, config.on_menu_canceled, FALSE, NULL);\n  } else if (state->retv & MENU_NEXT || state->retv & MENU_PREVIOUS ||\n             state->retv & MENU_QUICK_SWITCH || state->retv & MENU_COMPLETE) {\n    if (config.on_mode_changed == NULL)\n      return;\n    // TODO: pass mode name to custom command\n    helper_execute_command(NULL, config.on_mode_changed, FALSE, NULL);\n  }\n}\n\nvoid rofi_view_maybe_update(RofiViewState *state) {\n  if (rofi_view_get_completed(state)) {\n    // Exec custom user commands\n    rofi_quit_user_callback(state);\n    // This menu is done.\n    rofi_view_finalize(state);\n    // If there a state. (for example error) reload it.\n    state = rofi_view_get_active();\n\n    // cleanup, if no more state to display.\n    if (state == NULL) {\n      // Quit main-loop.\n      rofi_quit_main_loop();\n      return;\n    }\n  }\n\n  // Update if requested.\n  if (state->refilter) {\n    rofi_view_refilter(state);\n  }\n  rofi_view_update(state, TRUE);\n  return;\n}\nWidgetTriggerActionResult textbox_button_trigger_action(\n    widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,\n    G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = (RofiViewState *)user_data;\n  switch (action) {\n  case MOUSE_CLICK_DOWN: {\n    const char *type = rofi_theme_get_string(wid, \"action\", NULL);\n    if (type) {\n      if (state->list_view) {\n        (state->selected_line) =\n            state->line_map[listview_get_selected(state->list_view)];\n      } else {\n        (state->selected_line) = UINT32_MAX;\n      }\n      guint id = key_binding_get_action_from_name(type);\n      if (id != UINT32_MAX) {\n        rofi_view_trigger_global_action(id);\n      }\n      state->skip_absorb = TRUE;\n      return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n    }\n  }\n  case MOUSE_CLICK_UP:\n  case MOUSE_DCLICK_DOWN:\n  case MOUSE_DCLICK_UP:\n    break;\n  }\n  return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;\n}\nstatic WidgetTriggerActionResult textbox_sidebar_modes_trigger_action(\n    widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,\n    G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = (RofiViewState *)user_data;\n  unsigned int i;\n  for (i = 0; i < state->num_modes; i++) {\n    if (WIDGET(state->modes[i]) == wid) {\n      break;\n    }\n  }\n  if (i == state->num_modes) {\n    return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;\n  }\n\n  switch (action) {\n  case MOUSE_CLICK_DOWN:\n    state->retv = MENU_QUICK_SWITCH | (i & MENU_LOWER_MASK);\n    state->quit = TRUE;\n    state->skip_absorb = TRUE;\n    return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n  case MOUSE_CLICK_UP:\n  case MOUSE_DCLICK_DOWN:\n  case MOUSE_DCLICK_UP:\n    break;\n  }\n  return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;\n}\n\n// @TODO don't like this construction.\nstatic void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom,\n                                                  void *udata) {\n  RofiViewState *state = (RofiViewState *)udata;\n  state->retv = MENU_OK;\n  if (custom) {\n    state->retv |= MENU_CUSTOM_ACTION;\n  }\n  (state->selected_line) = state->line_map[listview_get_selected(lv)];\n  // Quit\n  state->quit = TRUE;\n  state->skip_absorb = TRUE;\n}\n\nstatic void rofi_view_add_widget(RofiViewState *state, widget *parent_widget,\n                                 const char *name) {\n  char *defaults = NULL;\n  widget *wid = NULL;\n\n  /**\n   * MAINBOX\n   */\n  if (strcmp(name, \"mainbox\") == 0) {\n    wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);\n    box_add((box *)parent_widget, WIDGET(wid), TRUE);\n    if (config.sidebar_mode) {\n      defaults = \"inputbar,message,listview,mode-switcher\";\n    } else {\n      defaults = \"inputbar,message,listview\";\n    }\n  }\n  /**\n   * INPUTBAR\n   */\n  else if (strcmp(name, \"inputbar\") == 0) {\n    wid =\n        (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);\n    defaults = \"prompt,entry,overlay,case-indicator\";\n    box_add((box *)parent_widget, WIDGET(wid), FALSE);\n  }\n  /**\n   * PROMPT\n   */\n  else if (strcmp(name, \"prompt\") == 0) {\n    if (state->prompt != NULL) {\n      g_error(\"Prompt widget can only be added once to the layout.\");\n      return;\n    }\n    // Prompt box.\n    state->prompt =\n        textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                       TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, \"\", 0, 0);\n    rofi_view_update_prompt(state);\n    box_add((box *)parent_widget, WIDGET(state->prompt), FALSE);\n    defaults = NULL;\n  } else if (strcmp(name, \"num-rows\") == 0) {\n    state->tb_total_rows =\n        textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                       TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, \"\", 0, 0);\n    box_add((box *)parent_widget, WIDGET(state->tb_total_rows), FALSE);\n    defaults = NULL;\n  } else if (strcmp(name, \"num-filtered-rows\") == 0) {\n    state->tb_filtered_rows =\n        textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                       TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, \"\", 0, 0);\n    box_add((box *)parent_widget, WIDGET(state->tb_filtered_rows), FALSE);\n    defaults = NULL;\n  } else if (strcmp(name, \"textbox-current-entry\") == 0) {\n    state->tb_current_entry =\n        textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                       TB_MARKUP | TB_AUTOHEIGHT, NORMAL, \"\", 0, 0);\n    box_add((box *)parent_widget, WIDGET(state->tb_current_entry), FALSE);\n    defaults = NULL;\n  } else if (strcmp(name, \"icon-current-entry\") == 0) {\n    state->icon_current_entry = icon_create(parent_widget, name);\n    box_add((box *)parent_widget, WIDGET(state->icon_current_entry), FALSE);\n    defaults = NULL;\n  }\n  /**\n   * CASE INDICATOR\n   */\n  else if (strcmp(name, \"case-indicator\") == 0) {\n    if (state->case_indicator != NULL) {\n      g_error(\"Case indicator widget can only be added once to the layout.\");\n      return;\n    }\n    state->case_indicator =\n        textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                       TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, \"*\", 0, 0);\n    // Add small separator between case indicator and text box.\n    box_add((box *)parent_widget, WIDGET(state->case_indicator), FALSE);\n    textbox_text(state->case_indicator, get_matching_state(state));\n  }\n  /**\n   * ENTRY BOX\n   */\n  else if (strcmp(name, \"entry\") == 0) {\n    if (state->text != NULL) {\n      g_error(\"Entry textbox widget can only be added once to the layout.\");\n      return;\n    }\n    // Entry box\n    TextboxFlags tfl = TB_EDITABLE;\n    tfl |= ((state->menu_flags & MENU_PASSWORD) == MENU_PASSWORD) ? TB_PASSWORD\n                                                                  : 0;\n    state->text = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,\n                                 tfl | TB_AUTOHEIGHT, NORMAL, NULL, 0, 0);\n    box_add((box *)parent_widget, WIDGET(state->text), TRUE);\n  }\n  /**\n   * MESSAGE\n   */\n  else if (strcmp(name, \"message\") == 0) {\n    if (state->mesg_box != NULL) {\n      g_error(\"Message widget can only be added once to the layout.\");\n      return;\n    }\n    state->mesg_box = container_create(parent_widget, name);\n    state->mesg_tb = textbox_create(\n        WIDGET(state->mesg_box), WIDGET_TYPE_TEXTBOX_TEXT, \"textbox\",\n        TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL, 0, 0);\n    container_add(state->mesg_box, WIDGET(state->mesg_tb));\n    rofi_view_reload_message_bar(state);\n    box_add((box *)parent_widget, WIDGET(state->mesg_box), FALSE);\n  }\n  /**\n   * LISTVIEW\n   */\n  else if (strcmp(name, \"listview\") == 0) {\n    if (state->list_view != NULL) {\n      g_error(\"Listview widget can only be added once to the layout.\");\n      return;\n    }\n    state->list_view =\n        listview_create(parent_widget, name, update_callback,\n                        page_changed_callback, state, config.element_height, 0);\n    listview_set_selection_changed_callback(\n        state->list_view, selection_changed_callback, (void *)state);\n    box_add((box *)parent_widget, WIDGET(state->list_view), TRUE);\n    listview_set_scroll_type(state->list_view, config.scroll_method);\n    listview_set_mouse_activated_cb(\n        state->list_view, rofi_view_listview_mouse_activated_cb, state);\n\n    listview_set_max_lines(state->list_view, state->num_lines);\n  }\n  /**\n   * MODE SWITCHER\n   */\n  else if (strcmp(name, \"mode-switcher\") == 0 || strcmp(name, \"sidebar\") == 0) {\n    if (state->sidebar_bar != NULL) {\n      g_error(\"Mode-switcher can only be added once to the layout.\");\n      return;\n    }\n    state->sidebar_bar =\n        box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);\n    box_add((box *)parent_widget, WIDGET(state->sidebar_bar), FALSE);\n    state->num_modes = rofi_get_num_enabled_modes();\n    state->modes = g_malloc0(state->num_modes * sizeof(textbox *));\n    for (unsigned int j = 0; j < state->num_modes; j++) {\n      const Mode *mode = rofi_get_mode(j);\n      state->modes[j] = textbox_create(\n          WIDGET(state->sidebar_bar), WIDGET_TYPE_MODE_SWITCHER, \"button\",\n          TB_AUTOHEIGHT, (mode == state->sw) ? HIGHLIGHT : NORMAL,\n          mode_get_display_name(mode), 0.5, 0.5);\n      box_add(state->sidebar_bar, WIDGET(state->modes[j]), TRUE);\n      widget_set_trigger_action_handler(\n          WIDGET(state->modes[j]), textbox_sidebar_modes_trigger_action, state);\n    }\n  } else if (g_ascii_strcasecmp(name, \"overlay\") == 0) {\n    state->overlay = textbox_create(\n        WIDGET(parent_widget), WIDGET_TYPE_TEXTBOX_TEXT, \"overlay\",\n        TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, \"blaat\", 0.5, 0);\n    box_add((box *)parent_widget, WIDGET(state->overlay), FALSE);\n    widget_disable(WIDGET(state->overlay));\n  } else if (g_ascii_strncasecmp(name, \"textbox\", 7) == 0) {\n    textbox *t = textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,\n                                TB_AUTOHEIGHT | TB_WRAP, NORMAL, \"\", 0, 0);\n    box_add((box *)parent_widget, WIDGET(t), TRUE);\n  } else if (g_ascii_strncasecmp(name, \"button\", 6) == 0) {\n    textbox *t = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,\n                                TB_AUTOHEIGHT | TB_WRAP, NORMAL, \"\", 0, 0);\n    box_add((box *)parent_widget, WIDGET(t), TRUE);\n    widget_set_trigger_action_handler(WIDGET(t), textbox_button_trigger_action,\n                                      state);\n  } else if (g_ascii_strncasecmp(name, \"icon\", 4) == 0) {\n    icon *t = icon_create(parent_widget, name);\n    /* small hack to make it clickable */\n    const char *type = rofi_theme_get_string(WIDGET(t), \"action\", NULL);\n    if (type) {\n      WIDGET(t)->type = WIDGET_TYPE_EDITBOX;\n    }\n    box_add((box *)parent_widget, WIDGET(t), TRUE);\n    widget_set_trigger_action_handler(WIDGET(t), textbox_button_trigger_action,\n                                      state);\n  } else {\n    wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);\n    box_add((box *)parent_widget, WIDGET(wid), TRUE);\n    // g_error(\"The widget %s does not exists. Invalid layout.\", name);\n  }\n  if (wid) {\n    GList *list = rofi_theme_get_list_strings(wid, \"children\");\n    if (list == NULL) {\n      if (defaults) {\n        char **a = g_strsplit(defaults, \",\", 0);\n        for (int i = 0; a && a[i]; i++) {\n          rofi_view_add_widget(state, wid, a[i]);\n        }\n        g_strfreev(a);\n      }\n    } else {\n      for (const GList *iter = g_list_first(list); iter != NULL;\n           iter = g_list_next(iter)) {\n        rofi_view_add_widget(state, wid, (const char *)iter->data);\n      }\n      g_list_free_full(list, g_free);\n    }\n  }\n}\n\nRofiViewState *rofi_view_create(Mode *sw, const char *input,\n                                MenuFlags menu_flags,\n                                void (*finalize)(RofiViewState *)) {\n  TICK();\n  RofiViewState *state = __rofi_view_state_create();\n  state->menu_flags = menu_flags;\n  state->sw = sw;\n  state->selected_line = UINT32_MAX;\n  state->previous_line = UINT32_MAX;\n  state->retv = MENU_CANCEL;\n  state->distance = NULL;\n  state->quit = FALSE;\n  state->skip_absorb = FALSE;\n  // We want to filter on the first run.\n  state->refilter = TRUE;\n  state->finalize = finalize;\n  state->mouse_seen = FALSE;\n\n  // In password mode, disable the entry history.\n  if ((menu_flags & MENU_PASSWORD) == MENU_PASSWORD) {\n    CacheState.entry_history_enable = FALSE;\n    g_debug(\"Disable entry history, because password setup.\");\n  }\n  if (config.disable_history) {\n    CacheState.entry_history_enable = FALSE;\n    g_debug(\"Disable entry history, because history disable flag.\");\n  }\n  // Request the lines to show.\n  state->num_lines = mode_get_num_entries(sw);\n\n  if (state->sw) {\n    char *title =\n        g_strdup_printf(\"rofi - %s\", mode_get_display_name(state->sw));\n    rofi_view_set_window_title(title);\n    g_free(title);\n  } else {\n    rofi_view_set_window_title(\"rofi\");\n  }\n  TICK_N(\"Startup notification\");\n\n  // Get active monitor size.\n  TICK_N(\"Get active monitor\");\n\n  state->main_window = box_create(NULL, \"window\", ROFI_ORIENTATION_VERTICAL);\n  // Get children.\n  GList *list =\n      rofi_theme_get_list_strings(WIDGET(state->main_window), \"children\");\n  if (list == NULL) {\n    rofi_view_add_widget(state, WIDGET(state->main_window), \"mainbox\");\n  } else {\n    for (const GList *iter = list; iter != NULL; iter = g_list_next(iter)) {\n      rofi_view_add_widget(state, WIDGET(state->main_window),\n                           (const char *)iter->data);\n    }\n    g_list_free_full(list, g_free);\n  }\n\n  if (state->text && input) {\n    textbox_text(state->text, input);\n    textbox_cursor_end(state->text);\n  }\n\n  // filtered list\n  state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));\n  state->distance = (int *)g_malloc0_n(state->num_lines, sizeof(int));\n\n  rofi_view_calculate_window_width(state);\n  // Only needed when window is fixed size.\n  if ((CacheState.flags & MENU_NORMAL_WINDOW) == MENU_NORMAL_WINDOW) {\n    listview_set_fixed_num_lines(state->list_view);\n  }\n\n  state->height = rofi_view_calculate_window_height(state);\n  // Move the window to the correct x,y position.\n  rofi_view_calculate_window_position(state);\n  rofi_view_window_update_size(state);\n\n  state->quit = FALSE;\n  rofi_view_refilter(state);\n  rofi_view_update(state, TRUE);\n#ifdef ENABLE_XCB\n  if (xcb->connection) {\n    xcb_map_window(xcb->connection, CacheState.main_window);\n  }\n#endif\n  widget_queue_redraw(WIDGET(state->main_window));\n  rofi_view_ping_mouse(state);\n#ifdef ENABLE_XCB\n  if (xcb->connection) {\n    xcb_flush(xcb->connection);\n  }\n#endif\n\n  rofi_view_set_user_timeout(NULL);\n  /* When Override Redirect, the WM will not let us know we can take focus, so\n   * just steal it */\n  if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {\n    display_set_input_focus(CacheState.main_window);\n  }\n\n#ifdef ENABLE_XCB\n  if (xcb->sncontext != NULL) {\n    sn_launchee_context_complete(xcb->sncontext);\n  }\n#endif\n  return state;\n}\n\nstatic void rofi_error_user_callback(const char *msg) {\n  if (config.on_menu_error == NULL)\n    return;\n\n  char **args = NULL;\n  int argv = 0;\n  helper_parse_setup(config.on_menu_error, &args, &argv, \"{error}\", msg,\n                     (char *)0);\n  if (args != NULL)\n    helper_execute(NULL, args, \"\", config.on_menu_error, NULL);\n}\n\nint rofi_view_error_dialog(const char *msg, int markup) {\n  RofiViewState *state = __rofi_view_state_create();\n  state->retv = MENU_CANCEL;\n  state->menu_flags = MENU_ERROR_DIALOG;\n  state->finalize = process_result;\n\n  state->main_window = box_create(NULL, \"window\", ROFI_ORIENTATION_VERTICAL);\n  box *new_box = box_create(WIDGET(state->main_window), \"error-message\",\n                            ROFI_ORIENTATION_VERTICAL);\n  box_add(state->main_window, WIDGET(new_box), TRUE);\n  state->text =\n      textbox_create(WIDGET(new_box), WIDGET_TYPE_TEXTBOX_TEXT, \"textbox\",\n                     (TB_AUTOHEIGHT | TB_WRAP) + ((markup) ? TB_MARKUP : 0),\n                     NORMAL, (msg != NULL) ? msg : \"\", 0, 0);\n  box_add(new_box, WIDGET(state->text), TRUE);\n\n  // Make sure we enable fixed num lines when in normal window mode.\n  if ((CacheState.flags & MENU_NORMAL_WINDOW) == MENU_NORMAL_WINDOW) {\n    listview_set_fixed_num_lines(state->list_view);\n  }\n  rofi_view_calculate_window_width(state);\n  state->height = rofi_view_calculate_window_height(state);\n\n  // Calculate window position.\n  rofi_view_calculate_window_position(state);\n\n  // Move the window to the correct x,y position.\n  rofi_view_window_update_size(state);\n\n#ifdef ENABLE_XCB\n  // Display it.\n  if (config.backend == DISPLAY_XCB) {\n    xcb_map_window(xcb->connection, CacheState.main_window);\n  }\n#endif\n  widget_queue_redraw(WIDGET(state->main_window));\n\n#ifdef ENABLE_XCB\n  if (xcb->sncontext != NULL) {\n    sn_launchee_context_complete(xcb->sncontext);\n  }\n#endif\n\n  // Exec custom command\n  rofi_error_user_callback(msg);\n\n  // Set it as current window.\n  rofi_view_set_active(state);\n  return TRUE;\n}\n\nstatic int rofi_thread_workers_sort(gconstpointer a, gconstpointer b,\n                                    gpointer data G_GNUC_UNUSED) {\n  thread_state *tsa = (thread_state *)a;\n  thread_state *tsb = (thread_state *)b;\n  // lower number is lower priority..  a is sorted above is a > b.\n  return tsa->priority - tsb->priority;\n}\n\nstatic void rofi_thread_pool_state_free(gpointer data) {\n  if (data) {\n    // This is a weirdness from glib that should not happen.\n    // It pushes in a 1 to msg sleeping threads to wake up.\n    // This should be removed from queue to avoid hitting this method.\n    // In practice, we still hit it (and crash)\n    if (GPOINTER_TO_UINT(data) == 1) {\n      // Ignore this entry.\n      g_debug(\"Glib thread-pool bug, received pointer with value 1.\");\n      return;\n    }\n    thread_state *ts = (thread_state *)data;\n    if (ts->free) {\n      ts->free(data);\n    }\n  }\n}\n\nvoid rofi_view_workers_initialize(void) {\n  TICK_N(\"Setup Threadpool, start\");\n  if (config.threads == 0) {\n    config.threads = 1;\n    long procs = sysconf(_SC_NPROCESSORS_CONF);\n    if (procs > 0) {\n      config.threads = MIN(procs, 128l);\n    }\n  }\n  // Create thread pool\n  GError *error = NULL;\n  tpool = g_thread_pool_new_full(rofi_view_call_thread, NULL,\n                                 rofi_thread_pool_state_free, config.threads,\n                                 FALSE, &error);\n  if (error == NULL) {\n    // Idle threads should stick around for a max of 60 seconds.\n    g_thread_pool_set_max_idle_time(60000);\n    // We are allowed to have\n    g_thread_pool_set_max_threads(tpool, config.threads, &error);\n  }\n  // If error occurred during setup of pool, tell user and exit.\n  if (error != NULL) {\n    g_warning(\"Failed to setup thread pool: '%s'\", error->message);\n    g_error_free(error);\n    exit(EXIT_FAILURE);\n  }\n  g_thread_pool_set_sort_function(tpool, rofi_thread_workers_sort, NULL);\n  TICK_N(\"Setup Threadpool, done\");\n}\nvoid rofi_view_workers_finalize(void) {\n  if (tpool) {\n    // Discard all unprocessed jobs and don't wait for current jobs in execution\n    g_thread_pool_free(tpool, TRUE, FALSE);\n    tpool = NULL;\n  }\n}\nMode *rofi_view_get_mode(RofiViewState *state) { return state->sw; }\n\nstatic gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state) {\n    widget_disable(WIDGET(state->overlay));\n  }\n  CacheState.overlay_timeout = 0;\n  rofi_view_queue_redraw();\n  return G_SOURCE_REMOVE;\n}\n\nvoid rofi_view_set_overlay_timeout(RofiViewState *state, const char *text) {\n  if (state->overlay == NULL || state->list_view == NULL) {\n    return;\n  }\n  if (text == NULL) {\n    widget_disable(WIDGET(state->overlay));\n    return;\n  }\n  rofi_view_set_overlay(state, text);\n  int timeout = rofi_theme_get_integer(WIDGET(state->overlay), \"timeout\", 3);\n  CacheState.overlay_timeout =\n      g_timeout_add_seconds(timeout, rofi_view_overlay_timeout, state);\n}\n\nvoid rofi_view_set_overlay(RofiViewState *state, const char *text) {\n  if (state->overlay == NULL || state->list_view == NULL) {\n    return;\n  }\n  if (CacheState.overlay_timeout > 0) {\n    g_source_remove(CacheState.overlay_timeout);\n    CacheState.overlay_timeout = 0;\n  }\n  if (text == NULL) {\n    widget_disable(WIDGET(state->overlay));\n    return;\n  }\n  widget_enable(WIDGET(state->overlay));\n  textbox_text(state->overlay, text);\n  // We want to queue a repaint.\n  rofi_view_queue_redraw();\n}\n\nvoid rofi_view_clear_input(RofiViewState *state) {\n  if (state->text) {\n    textbox_text(state->text, \"\");\n    rofi_view_set_selected_line(state, 0);\n  }\n}\n\nvoid rofi_view_ellipsize_listview(RofiViewState *state,\n                                  PangoEllipsizeMode mode) {\n  listview_set_ellipsize(state->list_view, mode);\n}\n\nvoid rofi_view_switch_mode(RofiViewState *state, Mode *mode) {\n  state->sw = mode;\n  // Update prompt;\n  if (state->prompt) {\n    rofi_view_update_prompt(state);\n  }\n  if (state->sw) {\n    char *title =\n        g_strdup_printf(\"rofi - %s\", mode_get_display_name(state->sw));\n    rofi_view_set_window_title(title);\n    g_free(title);\n  } else {\n    rofi_view_set_window_title(\"rofi\");\n  }\n  if (state->sidebar_bar) {\n    for (unsigned int j = 0; j < state->num_modes; j++) {\n      const Mode *tb_mode = rofi_get_mode(j);\n      textbox_font(state->modes[j],\n                   (tb_mode == state->sw) ? HIGHLIGHT : NORMAL);\n    }\n  }\n  rofi_view_restart(state);\n  state->reload = TRUE;\n  state->refilter = TRUE;\n  rofi_view_refilter_force(state);\n  rofi_view_update(state, TRUE);\n}\n\n/** ------ */\n\nvoid rofi_view_update(RofiViewState *state, gboolean qr) {\n  proxy->update(state, qr);\n}\n\nvoid rofi_view_temp_configure_notify(RofiViewState *state,\n                                     xcb_configure_notify_event_t *xce) {\n  proxy->temp_configure_notify(state, xce);\n}\n\nvoid rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target) {\n  proxy->temp_click_to_exit(state, target);\n}\n\nvoid rofi_view_frame_callback(void) { proxy->frame_callback(); }\n\nvoid rofi_view_queue_redraw(void) { proxy->queue_redraw(); }\n\nvoid rofi_view_set_window_title(const char *title) {\n  proxy->set_window_title(title);\n}\n\nvoid rofi_view_calculate_window_position(RofiViewState *state) {\n  proxy->calculate_window_position(state);\n}\n\nvoid rofi_view_calculate_window_width(struct RofiViewState *state) {\n  proxy->calculate_window_width(state);\n}\n\nint rofi_view_calculate_window_height(RofiViewState *state) {\n  return proxy->calculate_window_height(state);\n}\n\nvoid rofi_view_window_update_size(RofiViewState *state) {\n  proxy->window_update_size(state);\n}\n\nvoid rofi_view_set_cursor(RofiCursorType type) { proxy->set_cursor(type); }\n\nvoid rofi_view_cleanup(void) { proxy->cleanup(); }\n\nvoid rofi_view_hide(void) { proxy->hide(); }\n\nvoid rofi_view_reload(void) { proxy->reload(); }\n\nvoid __create_window(MenuFlags menu_flags) {\n  proxy->__create_window(menu_flags);\n}\n\nxcb_window_t rofi_view_get_window(void) { return proxy->get_window(); }\n\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  proxy->get_current_monitor(width, height);\n}\n\nvoid rofi_view_set_size(RofiViewState *state, gint width, gint height) {\n  proxy->set_size(state, width, height);\n}\n\nvoid rofi_view_get_size(RofiViewState *state, gint *width, gint *height) {\n  proxy->get_size(state, width, height);\n}\n\nvoid rofi_view_ping_mouse(RofiViewState *state) { proxy->ping_mouse(state); }\n\nvoid rofi_view_pool_refresh(void) { proxy->pool_refresh(); }\n"
  },
  {
    "path": "source/wayland/display.c",
    "content": "/**\n *   MIT/X11 License\n *   Modified  (c) 2017 Morgane Glidic, (c) 2020-2025 lbonn, (c) 2025 lvitals\n *\n *   Permission is hereby granted, free of charge, to any person obtaining\n *   a copy of this software and associated documentation files (the\n *   \"Software\"), to deal in the Software without restriction, including\n *   without limitation the rights to use, copy, modify, merge, publish,\n *   distribute, sublicense, and/or sell copies of the Software, and to\n *   permit persons to whom the Software is furnished to do so, subject to\n *   the following conditions:\n *\n *   The above copyright notice and this permission notice shall be\n *   included in all copies or substantial portions of the Software.\n *\n *   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n *   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n *   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n *   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n *   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n *   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#define G_LOG_DOMAIN \"Wayland\"\n#pragma GCC diagnostic ignored \"-Wunused-variable\"\n#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n\n#include <config.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <locale.h>\n#include <math.h>\n#include <stdint.h>\n#include <sys/mman.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <cairo.h>\n#include <glib.h>\n#include <glib/gstdio.h>\n#include <wayland-client.h>\n#include <wayland-cursor.h>\n#include <xkbcommon/xkbcommon-compose.h>\n#include <xkbcommon/xkbcommon.h>\n\n#include <libgwater-wayland.h>\n\n#include <nkutils-bindings.h>\n\n#include <rofi.h>\n\n#include \"input-codes.h\"\n#include \"keyb.h\"\n#include \"rofi-types.h\"\n#include \"settings.h\"\n#include \"view.h\"\n\n#include \"display-internal.h\"\n#include \"display.h\"\n#include \"wayland-internal.h\"\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n#include \"cursor-shape-v1-protocol.h\"\n#endif\n#include \"keyboard-shortcuts-inhibit-unstable-v1-protocol.h\"\n#include \"primary-selection-unstable-v1-protocol.h\"\n#include \"text-input-unstable-v3-protocol.h\"\n#include \"wlr-layer-shell-unstable-v1-protocol.h\"\n\n#define wayland_output_get_dpi(output, scale, dimension)                       \\\n  ((output)->current.physical_##dimension > 0 && (scale) > 0                   \\\n       ? round((double)(output)->current.dimension * 25.4 / (scale) /          \\\n               (output)->current.physical_##dimension)                         \\\n       : 0)\n\ntypedef struct _display_buffer_pool wayland_buffer_pool;\ntypedef struct {\n  wayland_stuff *context;\n  uint32_t global_name;\n  struct wl_output *output;\n  gchar *name;\n  struct {\n    int32_t x;\n    int32_t y;\n    int32_t width;\n    int32_t height;\n    int32_t physical_width;  /* mm */\n    int32_t physical_height; /* mm */\n    int32_t scale;\n    int32_t transform;\n  } current, pending;\n} wayland_output;\n\ntypedef struct {\n  wayland_buffer_pool *pool;\n  struct wl_buffer *buffer;\n  uint8_t *data;\n  gboolean released;\n} wayland_buffer;\n\nstruct _display_buffer_pool {\n  wayland_stuff *context;\n  uint8_t *data;\n  size_t size;\n  int32_t width;\n  int32_t height;\n  gboolean to_free;\n  wayland_buffer *buffers;\n};\n\nstatic gboolean wayland_display_late_setup(void);\n\nstatic wayland_stuff wayland_;\nwayland_stuff *wayland = &wayland_;\nstatic const cairo_user_data_key_t wayland_cairo_surface_user_data;\n\nstatic const struct zwp_text_input_v3_listener text_input_listener;\n\nstatic void wayland_buffer_cleanup(wayland_buffer_pool *self) {\n  if (!self->to_free) {\n    return;\n  }\n\n  size_t i, count = 0;\n  for (i = 0; i < wayland->buffer_count; ++i) {\n    if ((self->buffers[i].released) && (self->buffers[i].buffer != NULL)) {\n      wl_buffer_destroy(self->buffers[i].buffer);\n      self->buffers[i].buffer = NULL;\n    }\n    if (self->buffers[i].buffer == NULL) {\n      ++count;\n    }\n  }\n\n  if (count < wayland->buffer_count) {\n    return;\n  }\n\n  munmap(self->data, self->size);\n  g_free(self);\n}\n\nstatic void wayland_buffer_release(void *data, struct wl_buffer *buffer) {\n  wayland_buffer_pool *self = data;\n\n  size_t i;\n  for (i = 0; i < wayland->buffer_count; ++i) {\n    if (self->buffers[i].buffer == buffer) {\n      self->buffers[i].released = TRUE;\n    }\n  }\n\n  wayland_buffer_cleanup(self);\n}\n\nstatic const struct wl_buffer_listener wayland_buffer_listener = {\n    wayland_buffer_release};\n\nwayland_buffer_pool *display_buffer_pool_new(gint width, gint height) {\n  struct wl_shm_pool *wl_pool;\n  struct wl_buffer *buffer;\n  int fd;\n  uint8_t *data;\n  width *= wayland->scale;\n  height *= wayland->scale;\n  int32_t stride;\n  size_t size;\n  size_t pool_size;\n\n  stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);\n  if (stride < 0) {\n    g_warning(\"cairo stride width calculation failure\");\n    return NULL;\n  }\n  size = (size_t)stride * height;\n  pool_size = size * wayland->buffer_count;\n\n  gchar filename[PATH_MAX];\n  g_snprintf(filename, PATH_MAX, \"%s/rofi-wayland-surface\",\n             g_get_user_runtime_dir());\n  fd = g_open(filename, O_CREAT | O_RDWR, 0);\n  g_unlink(filename);\n  if (fd < 0) {\n    g_warning(\"creating a buffer file for %zu B failed: %s\", pool_size,\n              g_strerror(errno));\n    return NULL;\n  }\n  if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {\n    g_close(fd, NULL);\n    return NULL;\n  }\n  if (ftruncate(fd, pool_size) < 0) {\n    g_close(fd, NULL);\n    return NULL;\n  }\n\n  data = mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);\n  if (data == MAP_FAILED) {\n    g_warning(\"mmap of size %zu failed: %s\", pool_size, g_strerror(errno));\n    close(fd);\n    return NULL;\n  }\n\n  wayland_buffer_pool *pool;\n  pool = g_new0(wayland_buffer_pool, 1);\n  pool->data = data;\n  pool->size = pool_size;\n\n  pool->width = width;\n  pool->height = height;\n\n  pool->buffers = g_new0(wayland_buffer, wayland->buffer_count);\n\n  wl_pool = wl_shm_create_pool(wayland->shm, fd, pool_size);\n  size_t i;\n  for (i = 0; i < wayland->buffer_count; ++i) {\n    pool->buffers[i].pool = pool;\n    pool->buffers[i].buffer = wl_shm_pool_create_buffer(\n        wl_pool, size * i, width, height, stride, WL_SHM_FORMAT_ARGB8888);\n    pool->buffers[i].data = data + size * i;\n    pool->buffers[i].released = TRUE;\n    wl_buffer_add_listener(pool->buffers[i].buffer, &wayland_buffer_listener,\n                           pool);\n  }\n  wl_shm_pool_destroy(wl_pool);\n  close(fd);\n\n  return pool;\n}\n\nvoid display_buffer_pool_free(wayland_buffer_pool *self) {\n  if (self == NULL) {\n    return;\n  }\n  self->to_free = TRUE;\n  wayland_buffer_cleanup(self);\n}\n\nstatic void wayland_surface_protocol_enter(void *data,\n                                           struct wl_surface *wl_surface,\n                                           struct wl_output *wl_output) {\n  wayland_output *output;\n\n  output = g_hash_table_lookup(wayland->outputs, wl_output);\n  if (output == NULL) {\n    return;\n  }\n\n  if (config.dpi == 0 || config.dpi == 1) {\n    // DPI auto-detect requested.\n    config.dpi = wayland_output_get_dpi(output, output->current.scale, height);\n    g_debug(\"Auto-detected DPI: %d\", config.dpi);\n  }\n\n  wl_surface_set_buffer_scale(wl_surface, output->current.scale);\n\n  if (wayland->scale != output->current.scale) {\n    wayland->scale = output->current.scale;\n\n    // create new buffers with the correct scaled size\n    rofi_view_pool_refresh();\n\n    RofiViewState *state = rofi_view_get_active();\n    if (state != NULL) {\n      rofi_view_set_size(state, -1, -1);\n    }\n  }\n}\n\nstatic void wayland_surface_protocol_leave(void *data,\n                                           struct wl_surface *wl_surface,\n                                           struct wl_output *wl_output) {}\n\nstatic const struct wl_surface_listener wayland_surface_interface = {\n    .enter = wayland_surface_protocol_enter,\n    .leave = wayland_surface_protocol_leave,\n};\n\nstatic void wayland_frame_callback(void *data, struct wl_callback *callback,\n                                   uint32_t time);\n\nstatic const struct wl_callback_listener wayland_frame_wl_callback_listener = {\n    .done = wayland_frame_callback,\n};\n\ncairo_surface_t *\ndisplay_buffer_pool_get_next_buffer(wayland_buffer_pool *pool) {\n  wayland_buffer *buffer = NULL;\n  size_t i;\n  for (i = 0; (buffer == NULL) && (i < wayland->buffer_count); ++i) {\n    buffer = pool->buffers + i;\n    if (!buffer->released) {\n      buffer = NULL;\n    }\n  }\n  if (buffer == NULL) {\n    return NULL;\n  }\n\n  cairo_surface_t *surface;\n\n  surface = cairo_image_surface_create_for_data(\n      buffer->data, CAIRO_FORMAT_ARGB32, pool->width, pool->height,\n      cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pool->width));\n  cairo_surface_set_user_data(surface, &wayland_cairo_surface_user_data, buffer,\n                              NULL);\n  return surface;\n}\n\nvoid display_surface_commit(cairo_surface_t *surface) {\n  if (surface == NULL || wayland->surface == NULL) {\n    return;\n  }\n\n  wayland_buffer *buffer =\n      cairo_surface_get_user_data(surface, &wayland_cairo_surface_user_data);\n  wayland_buffer_pool *pool = buffer->pool;\n\n  cairo_surface_destroy(surface);\n\n  wl_surface_damage(wayland->surface, 0, 0, pool->width, pool->height);\n  wl_surface_attach(wayland->surface, buffer->buffer, 0, 0);\n  // FIXME: hidpi\n  wl_surface_set_buffer_scale(wayland->surface, wayland->scale);\n  buffer->released = FALSE;\n\n  wl_surface_commit(wayland->surface);\n}\n\nstatic void wayland_frame_callback(void *data, struct wl_callback *callback,\n                                   uint32_t timestamp) {\n  if (wayland->frame_cb != NULL) {\n    wl_callback_destroy(wayland->frame_cb);\n    wayland->frame_cb = NULL;\n    rofi_view_frame_callback();\n  }\n  if (wayland->surface != NULL) {\n    wayland->frame_cb = wl_surface_frame(wayland->surface);\n    wl_callback_add_listener(wayland->frame_cb,\n                             &wayland_frame_wl_callback_listener, wayland);\n  }\n}\n\nstatic void wayland_keyboard_keymap(void *data, struct wl_keyboard *keyboard,\n                                    enum wl_keyboard_keymap_format format,\n                                    int32_t fd, uint32_t size) {\n  if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {\n    close(fd);\n    return;\n  }\n\n  char *str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);\n  if (str == MAP_FAILED) {\n    close(fd);\n    return;\n  }\n\n  struct xkb_keymap *keymap = xkb_keymap_new_from_string(\n      nk_bindings_seat_get_context(wayland->bindings_seat), str,\n      XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);\n  if (keymap == NULL) {\n    fprintf(stderr, \"Failed to get Keymap for current keyboard device.\\n\");\n    return;\n  }\n  struct xkb_state *state = xkb_state_new(keymap);\n  if (state == NULL) {\n    fprintf(stderr,\n            \"Failed to get state object for current keyboard device.\\n\");\n    return;\n  }\n\n  nk_bindings_seat_update_keymap(wayland->bindings_seat, keymap, state);\n}\n\nstatic void wayland_keyboard_enter(void *data, struct wl_keyboard *keyboard,\n                                   uint32_t serial, struct wl_surface *surface,\n                                   struct wl_array *keys) {\n  wayland_seat *self = data;\n\n  wayland->last_seat = self;\n  self->serial = serial;\n\n  uint32_t *key, *kend;\n  for (key = keys->data, kend = key + keys->size / sizeof(*key); key < kend;\n       ++key) {\n    nk_bindings_seat_handle_key(wayland->bindings_seat, NULL, *key + 8,\n                                NK_BINDINGS_KEY_STATE_PRESSED);\n  }\n}\n\nstatic void wayland_keyboard_leave(void *data, struct wl_keyboard *keyboard,\n                                   uint32_t serial,\n                                   struct wl_surface *surface) {\n  wayland_seat *self = data;\n  // TODO?\n}\n\nstatic gboolean wayland_key_repeat(void *data) {\n  wayland_seat *self = data;\n\n  if (self->repeat.key == 0) {\n    self->repeat.source = NULL;\n    return G_SOURCE_REMOVE;\n  }\n\n  char *text = nk_bindings_seat_handle_key(wayland->bindings_seat, NULL,\n                                           self->repeat.key,\n                                           NK_BINDINGS_KEY_STATE_PRESS);\n\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return G_SOURCE_REMOVE;\n  }\n\n  if (text != NULL) {\n    rofi_view_handle_text(state, text);\n  }\n\n  rofi_view_maybe_update(state);\n\n  return G_SOURCE_CONTINUE;\n}\n\nstatic gboolean wayland_key_repeat_delay(void *data) {\n  wayland_seat *self = data;\n\n  if (self->repeat.key == 0) {\n    return FALSE;\n  }\n\n  char *text = nk_bindings_seat_handle_key(wayland->bindings_seat, NULL,\n                                           self->repeat.key,\n                                           NK_BINDINGS_KEY_STATE_PRESS);\n\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return G_SOURCE_REMOVE;\n  }\n\n  if (text != NULL) {\n    rofi_view_handle_text(state, text);\n  }\n\n  guint repeat_wait_ms = 30;\n  if (self->repeat.rate != 0) {\n    repeat_wait_ms = 1000 / self->repeat.rate;\n  }\n  guint source_id = g_timeout_add(repeat_wait_ms, wayland_key_repeat, data);\n  self->repeat.source = g_main_context_find_source_by_id(NULL, source_id);\n\n  rofi_view_maybe_update(state);\n\n  return G_SOURCE_REMOVE;\n}\n\nstatic void wayland_keyboard_key(void *data, struct wl_keyboard *keyboard,\n                                 uint32_t serial, uint32_t time, uint32_t key,\n                                 enum wl_keyboard_key_state kstate) {\n  RofiViewState *state = rofi_view_get_active();\n  wayland_seat *self = data;\n\n  wayland->last_seat = self;\n  self->serial = serial;\n\n  xkb_keycode_t keycode = key + 8;\n  if (kstate == WL_KEYBOARD_KEY_STATE_RELEASED) {\n    if (keycode == self->repeat.key) {\n      self->repeat.key = 0;\n      if (self->repeat.source != NULL) {\n        g_source_destroy(self->repeat.source);\n        self->repeat.source = NULL;\n      }\n    }\n    nk_bindings_seat_handle_key(wayland->bindings_seat, NULL, keycode,\n                                NK_BINDINGS_KEY_STATE_RELEASE);\n  } else if (kstate == WL_KEYBOARD_KEY_STATE_PRESSED) {\n    gchar *text = nk_bindings_seat_handle_key(\n        wayland->bindings_seat, NULL, keycode, NK_BINDINGS_KEY_STATE_PRESS);\n\n    if (self->repeat.source != NULL) {\n      g_source_destroy(self->repeat.source);\n      self->repeat.source = NULL;\n    }\n\n    if (state != NULL) {\n      if (text != NULL) {\n        rofi_view_handle_text(state, text);\n      }\n      self->repeat.key = keycode;\n      guint source_id =\n          g_timeout_add(self->repeat.delay, wayland_key_repeat_delay, data);\n      self->repeat.source = g_main_context_find_source_by_id(NULL, source_id);\n    }\n  }\n\n  if (state != NULL) {\n    rofi_view_maybe_update(state);\n  }\n}\n\nstatic void wayland_keyboard_modifiers(void *data, struct wl_keyboard *keyboard,\n                                       uint32_t serial, uint32_t mods_depressed,\n                                       uint32_t mods_latched,\n                                       uint32_t mods_locked, uint32_t group) {\n  wayland_seat *self = data;\n  nk_bindings_seat_update_mask(wayland->bindings_seat, NULL, mods_depressed,\n                               mods_latched, mods_locked, 0, 0, group);\n\n  RofiViewState *state = rofi_view_get_active();\n  if (state != NULL) {\n    rofi_view_maybe_update(state);\n  }\n}\n\nstatic void wayland_keyboard_repeat_info(void *data,\n                                         struct wl_keyboard *keyboard,\n                                         int32_t rate, int32_t delay) {\n  wayland_seat *self = data;\n  self->repeat.key = 0;\n  self->repeat.rate = rate;\n  self->repeat.delay = delay;\n  if (self->repeat.source != NULL) {\n    g_source_destroy(self->repeat.source);\n    self->repeat.source = NULL;\n  }\n}\n\nstatic const struct wl_keyboard_listener wayland_keyboard_listener = {\n    .keymap = wayland_keyboard_keymap,\n    .enter = wayland_keyboard_enter,\n    .leave = wayland_keyboard_leave,\n    .key = wayland_keyboard_key,\n    .modifiers = wayland_keyboard_modifiers,\n    .repeat_info = wayland_keyboard_repeat_info,\n};\n\nstatic gboolean wayland_cursor_reload_theme(guint scale);\n\nstatic void wayland_cursor_set_image(int i) {\n  struct wl_buffer *buffer;\n  struct wl_cursor_image *image;\n  image = wayland->cursor.cursor->images[i];\n\n  wayland->cursor.image = image;\n  buffer = wl_cursor_image_get_buffer(wayland->cursor.image);\n  wl_surface_set_buffer_scale(wayland->cursor.surface, wayland->scale);\n  wl_surface_attach(wayland->cursor.surface, buffer, 0, 0);\n  wl_surface_damage(wayland->cursor.surface, 0, 0, wayland->cursor.image->width,\n                    wayland->cursor.image->height);\n  wl_surface_commit(wayland->cursor.surface);\n}\n\nstatic void wayland_cursor_frame_callback(void *data,\n                                          struct wl_callback *callback,\n                                          uint32_t time);\n\nstatic const struct wl_callback_listener\n    wayland_cursor_frame_wl_callback_listener = {\n        .done = wayland_cursor_frame_callback,\n};\n\nstatic void wayland_cursor_frame_callback(void *data,\n                                          struct wl_callback *callback,\n                                          uint32_t time) {\n  int i;\n\n  if (wayland->cursor.frame_cb != NULL) {\n    wl_callback_destroy(wayland->cursor.frame_cb);\n  }\n  wayland->cursor.frame_cb = wl_surface_frame(wayland->cursor.surface);\n  wl_callback_add_listener(wayland->cursor.frame_cb,\n                           &wayland_cursor_frame_wl_callback_listener, wayland);\n\n  i = wl_cursor_frame(wayland->cursor.cursor, time);\n  wayland_cursor_set_image(i);\n}\n\nstatic void wayland_pointer_send_events(wayland_seat *self) {\n  RofiViewState *state = rofi_view_get_active();\n\n  if (state == NULL) {\n    return;\n  }\n\n  if (self->motion.x > -1 || self->motion.y > -1) {\n    rofi_view_handle_mouse_motion(state, self->motion.x, self->motion.y,\n                                  config.hover_select);\n    self->motion.x = -1;\n    self->motion.y = -1;\n  }\n\n  NkBindingsMouseButton button = -1;\n  switch (self->button.button) {\n  case BTN_LEFT:\n    button = NK_BINDINGS_MOUSE_BUTTON_PRIMARY;\n    break;\n  case BTN_RIGHT:\n    button = NK_BINDINGS_MOUSE_BUTTON_SECONDARY;\n    break;\n  case BTN_MIDDLE:\n    button = NK_BINDINGS_MOUSE_BUTTON_MIDDLE;\n    break;\n  }\n\n  if (self->button.button > 0) {\n    if (self->button.pressed) {\n      rofi_view_handle_mouse_motion(state, self->button.x, self->button.y,\n                                    FALSE);\n      nk_bindings_seat_handle_button(wayland->bindings_seat, NULL, button,\n                                     NK_BINDINGS_BUTTON_STATE_PRESS,\n                                     self->button.time);\n    } else {\n      nk_bindings_seat_handle_button(wayland->bindings_seat, NULL, button,\n                                     NK_BINDINGS_BUTTON_STATE_RELEASE,\n                                     self->button.time);\n    }\n    self->button.button = 0;\n  }\n\n  if (self->axis_source == WL_POINTER_AXIS_SOURCE_FINGER ||\n      self->axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) {\n    self->wheel.vertical += 20 * self->wheel_continuous.vertical;\n    self->wheel.horizontal += 20 * self->wheel_continuous.horizontal;\n  }\n\n  if (abs(self->wheel.vertical) >= 120) {\n    gint v120 = self->wheel.vertical;\n    nk_bindings_seat_handle_scroll(wayland->bindings_seat, NULL,\n                                   NK_BINDINGS_SCROLL_AXIS_VERTICAL,\n                                   v120 / 120);\n    if (v120 > 0) {\n      self->wheel.vertical = v120 % 120;\n    } else {\n      self->wheel.vertical = -((-v120) % 120);\n    }\n  }\n\n  if (abs(self->wheel.horizontal) >= 120) {\n    gint v120 = self->wheel.horizontal;\n    nk_bindings_seat_handle_scroll(wayland->bindings_seat, NULL,\n                                   NK_BINDINGS_SCROLL_AXIS_HORIZONTAL,\n                                   v120 / 120);\n    if (v120 > 0) {\n      self->wheel.horizontal = v120 % 120;\n    } else {\n      self->wheel.horizontal = -((-v120) % 120);\n    }\n  }\n\n  self->axis_source = 0;\n  self->wheel_continuous.vertical = 0;\n  self->wheel_continuous.horizontal = 0;\n\n  rofi_view_maybe_update(state);\n}\n\nstatic struct wl_cursor *\nrofi_cursor_type_to_wl_cursor(struct wl_cursor_theme *theme,\n                              RofiCursorType type) {\n  static const char *const default_names[] = {\n      \"default\", \"left_ptr\", \"top_left_arrow\", \"left-arrow\", NULL};\n  static const char *const pointer_names[] = {\"pointer\", \"hand1\", NULL};\n  static const char *const text_names[] = {\"text\", \"xterm\", NULL};\n\n  const char *const *name;\n  struct wl_cursor *cursor = NULL;\n\n  switch (type) {\n  case ROFI_CURSOR_POINTER:\n    name = pointer_names;\n    break;\n  case ROFI_CURSOR_TEXT:\n    name = text_names;\n    break;\n  default:\n    name = default_names;\n    break;\n  }\n  for (; cursor == NULL && *name != NULL; ++name) {\n    cursor = wl_cursor_theme_get_cursor(theme, *name);\n  }\n  return cursor;\n}\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\nstatic enum wp_cursor_shape_device_v1_shape\nrofi_cursor_type_to_wp_cursor_shape(RofiCursorType type) {\n  switch (type) {\n  case ROFI_CURSOR_POINTER:\n    return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;\n  case ROFI_CURSOR_TEXT:\n    return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;\n  default:\n    return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;\n  }\n}\n#endif\n\nstatic void wayland_cursor_update_for_seat(wayland_seat *seat) {\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  if (seat->cursor_shape_device != NULL) {\n    wp_cursor_shape_device_v1_set_shape(\n        seat->cursor_shape_device, seat->pointer_serial,\n        rofi_cursor_type_to_wp_cursor_shape(wayland->cursor.type));\n    return;\n  } else if (wayland->cursor.theme == NULL) {\n    // cursor-shape-v1 is available, but the seat haven't seen a pointer yet\n    return;\n  }\n#endif\n\n  if (wayland->cursor.surface == NULL) {\n    wayland->cursor.surface = wl_compositor_create_surface(wayland->compositor);\n  }\n\n  if (wayland->cursor.cursor->image_count < 2) {\n    wayland_cursor_set_image(0);\n  } else {\n    wayland_cursor_frame_callback(wayland, wayland->cursor.frame_cb, 0);\n  }\n\n  wl_pointer_set_cursor(\n      seat->pointer, seat->pointer_serial, wayland->cursor.surface,\n      wayland->cursor.image->hotspot_x / wayland->cursor.scale,\n      wayland->cursor.image->hotspot_y / wayland->cursor.scale);\n}\n\nstatic void wayland_pointer_enter(void *data, struct wl_pointer *pointer,\n                                  uint32_t serial, struct wl_surface *surface,\n                                  wl_fixed_t x, wl_fixed_t y) {\n  wayland_seat *self = data;\n\n  self->pointer_serial = serial;\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  if (wayland->cursor_shape_manager != NULL) {\n    if (self->cursor_shape_device == NULL) {\n      self->cursor_shape_device = wp_cursor_shape_manager_v1_get_pointer(\n          wayland->cursor_shape_manager, pointer);\n    }\n  } else\n#endif\n      if (!wayland_cursor_reload_theme(wayland->scale)) {\n    return;\n  }\n\n  wayland_cursor_update_for_seat(self);\n}\n\nvoid wayland_display_set_cursor_type(RofiCursorType type) {\n  wayland_seat *seat;\n  GHashTableIter iter;\n  struct wl_cursor *cursor;\n\n  if (wayland->cursor.type == type) {\n    return;\n  }\n  wayland->cursor.type = type;\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  if (wayland->cursor_shape_manager == NULL)\n#endif\n  {\n    if (wayland->cursor.theme == NULL) {\n      return;\n    }\n\n    cursor = rofi_cursor_type_to_wl_cursor(wayland->cursor.theme, type);\n    if (cursor == NULL) {\n      g_info(\"Failed to load cursor type %d\", type);\n      return;\n    }\n    wayland->cursor.cursor = cursor;\n  }\n\n  g_hash_table_iter_init(&iter, wayland->seats);\n  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&seat)) {\n    if (seat->pointer != NULL) {\n      wayland_cursor_update_for_seat(seat);\n    }\n  }\n}\n\nstatic void wayland_pointer_leave(void *data, struct wl_pointer *pointer,\n                                  uint32_t serial, struct wl_surface *surface) {\n  wayland_seat *self = data;\n\n  if (wayland->cursor.frame_cb != NULL) {\n    wl_callback_destroy(wayland->cursor.frame_cb);\n    wayland->cursor.frame_cb = NULL;\n  }\n}\n\nstatic void wayland_pointer_motion(void *data, struct wl_pointer *pointer,\n                                   uint32_t time, wl_fixed_t x, wl_fixed_t y) {\n  wayland_seat *self = data;\n\n  self->button.x = wl_fixed_to_int(x);\n  self->button.y = wl_fixed_to_int(y);\n  self->motion.x = wl_fixed_to_int(x);\n  self->motion.y = wl_fixed_to_int(y);\n  self->motion.time = time;\n}\n\nstatic void wayland_pointer_button(void *data, struct wl_pointer *pointer,\n                                   uint32_t serial, uint32_t time,\n                                   uint32_t button,\n                                   enum wl_pointer_button_state state) {\n  wayland_seat *self = data;\n\n  wayland->last_seat = self;\n  self->serial = serial;\n\n  self->button.time = time;\n  self->button.pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);\n  self->button.button = button;\n}\n\nstatic void wayland_pointer_axis(void *data, struct wl_pointer *pointer,\n                                 uint32_t time, enum wl_pointer_axis axis,\n                                 wl_fixed_t value) {\n  wayland_seat *self = data;\n\n  switch (axis) {\n  case WL_POINTER_AXIS_VERTICAL_SCROLL:\n    self->wheel_continuous.vertical += wl_fixed_to_double(value);\n    break;\n  case WL_POINTER_AXIS_HORIZONTAL_SCROLL:\n    self->wheel_continuous.horizontal += wl_fixed_to_double(value);\n    break;\n  }\n}\n\nstatic void wayland_pointer_frame(void *data, struct wl_pointer *pointer) {\n  wayland_seat *self = data;\n  wayland_pointer_send_events(self);\n}\n\nstatic void\nwayland_pointer_axis_source(void *data, struct wl_pointer *pointer,\n                            enum wl_pointer_axis_source axis_source) {\n\n  wayland_seat *self = data;\n  self->axis_source = axis_source;\n}\n\nstatic void wayland_pointer_axis_stop(void *data, struct wl_pointer *pointer,\n                                      uint32_t time,\n                                      enum wl_pointer_axis axis) {}\n\nstatic void wayland_pointer_axis_discrete(void *data,\n                                          struct wl_pointer *pointer,\n                                          enum wl_pointer_axis axis,\n                                          int32_t discrete) {\n  wayland_seat *self = data;\n\n  // values are multiplied by 120 for compatibility with the\n  // new high-resolution events\n  switch (axis) {\n  case WL_POINTER_AXIS_VERTICAL_SCROLL:\n    self->wheel.vertical += discrete * 120;\n    break;\n  case WL_POINTER_AXIS_HORIZONTAL_SCROLL:\n    self->wheel.horizontal += discrete * 120;\n    break;\n  }\n}\n\n#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION\nstatic void wayland_pointer_axis120(void *data, struct wl_pointer *wl_pointer,\n                                    enum wl_pointer_axis axis,\n                                    int32_t value120) {\n  wayland_seat *self = data;\n\n  switch (axis) {\n  case WL_POINTER_AXIS_VERTICAL_SCROLL:\n    self->wheel.vertical += value120;\n    break;\n  case WL_POINTER_AXIS_HORIZONTAL_SCROLL:\n    self->wheel.horizontal += value120;\n    break;\n  }\n}\n#endif\n\nstatic const struct wl_pointer_listener wayland_pointer_listener = {\n    .enter = wayland_pointer_enter,\n    .leave = wayland_pointer_leave,\n    .motion = wayland_pointer_motion,\n    .button = wayland_pointer_button,\n    .axis = wayland_pointer_axis,\n    .frame = wayland_pointer_frame,\n    .axis_source = wayland_pointer_axis_source,\n    .axis_stop = wayland_pointer_axis_stop,\n#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION\n    .axis_value120 = wayland_pointer_axis120,\n#endif\n    .axis_discrete = wayland_pointer_axis_discrete,\n};\n\nstatic void wayland_keyboard_release(wayland_seat *self) {\n  if (self->keyboard == NULL) {\n    return;\n  }\n\n  wl_keyboard_release(self->keyboard);\n\n  self->repeat.key = 0;\n  if (self->repeat.source != NULL) {\n    g_source_destroy(self->repeat.source);\n    self->repeat.source = NULL;\n  }\n\n  self->keyboard = NULL;\n}\n\n#define CLIPBOARD_READ_INCREMENT 1024\n\nstruct clipboard_read_info {\n  char *buffer;\n  size_t size;\n  int fd;\n  ClipboardCb callback;\n  void *user_data;\n};\n\nstatic gboolean clipboard_read_glib_callback(GIOChannel *channel,\n                                             GIOCondition condition,\n                                             gpointer opaque) {\n  struct clipboard_read_info *info = opaque;\n  gsize read;\n\n  GIOStatus status =\n      g_io_channel_read_chars(channel, info->buffer + info->size,\n                              CLIPBOARD_READ_INCREMENT, &read, NULL);\n  switch (status) {\n  case G_IO_STATUS_AGAIN:\n    return TRUE;\n\n  case G_IO_STATUS_NORMAL: {\n    info->size += read;\n    info->buffer =\n        g_realloc(info->buffer, info->size + CLIPBOARD_READ_INCREMENT);\n    if (!info->buffer) {\n      g_io_channel_shutdown(channel, FALSE, NULL);\n      g_io_channel_unref(channel);\n      close(info->fd);\n      g_free(info);\n      return FALSE;\n    }\n    return TRUE;\n  }\n\n  default:\n    info->buffer[info->size] = '\\0';\n    if (status == G_IO_STATUS_EOF) {\n      info->callback(info->buffer, info->user_data);\n    } else { // G_IO_STATUS_ERROR\n      g_warning(\"Could not read data from clipboard\");\n      g_free(info->buffer);\n    }\n    g_io_channel_shutdown(channel, FALSE, NULL);\n    g_io_channel_unref(channel);\n    close(info->fd);\n    g_free(info);\n    return FALSE;\n  }\n}\n\nstatic gboolean clipboard_read_data(int fd, ClipboardCb callback,\n                                    void *user_data) {\n  GIOChannel *channel = g_io_channel_unix_new(fd);\n\n  struct clipboard_read_info *info = g_malloc(sizeof *info);\n  if (info == NULL) {\n    g_io_channel_unref(channel);\n    close(fd);\n    return FALSE;\n  }\n\n  info->fd = fd;\n  info->size = 0;\n  info->callback = callback;\n  info->user_data = user_data;\n  info->buffer = g_malloc(CLIPBOARD_READ_INCREMENT);\n\n  if (info->buffer == NULL) {\n    g_io_channel_unref(channel);\n    close(info->fd);\n    g_free(info);\n    return FALSE;\n  }\n\n  g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR,\n                 clipboard_read_glib_callback, info);\n\n  return TRUE;\n}\n\nstatic void data_offer_handle_offer(void *data, struct wl_data_offer *offer,\n                                    const char *mime_type) {}\n\nstatic void data_offer_handle_source_actions(\n    void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions) {}\n\nstatic void data_offer_handle_action(void *data,\n                                     struct wl_data_offer *wl_data_offer,\n                                     uint32_t dnd_action) {}\n\nstatic const struct wl_data_offer_listener data_offer_listener = {\n    .offer = data_offer_handle_offer,\n    .source_actions = data_offer_handle_source_actions,\n    .action = data_offer_handle_action,\n};\n\nstatic void data_device_handle_data_offer(void *data,\n                                          struct wl_data_device *data_device,\n                                          struct wl_data_offer *offer) {\n  wl_data_offer_add_listener(offer, &data_offer_listener, NULL);\n}\n\nstatic void data_device_handle_enter(void *data,\n                                     struct wl_data_device *wl_data_device,\n                                     uint32_t serial,\n                                     struct wl_surface *surface, wl_fixed_t x,\n                                     wl_fixed_t y, struct wl_data_offer *id) {}\n\nstatic void data_device_handle_leave(void *data,\n                                     struct wl_data_device *wl_data_device) {}\n\nstatic void data_device_handle_motion(void *data,\n                                      struct wl_data_device *wl_data_device,\n                                      uint32_t time, wl_fixed_t x,\n                                      wl_fixed_t y) {}\n\nstatic void data_device_handle_drop(void *data,\n                                    struct wl_data_device *wl_data_device) {}\n\nstatic void clipboard_handle_selection(enum clipboard_type cb_type,\n                                       void *offer) {\n  clipboard_data *clipboard = &wayland->clipboards[cb_type];\n\n  if (clipboard->offer != NULL) {\n    if (cb_type == CLIPBOARD_DEFAULT) {\n      wl_data_offer_destroy(clipboard->offer);\n    } else {\n      zwp_primary_selection_offer_v1_destroy(clipboard->offer);\n    }\n  }\n  clipboard->offer = offer;\n}\n\nstatic void data_device_handle_selection(void *data,\n                                         struct wl_data_device *data_device,\n                                         struct wl_data_offer *offer) {\n  clipboard_handle_selection(CLIPBOARD_DEFAULT, offer);\n}\n\nstatic const struct wl_data_device_listener data_device_listener = {\n    .data_offer = data_device_handle_data_offer,\n    .enter = data_device_handle_enter,\n    .leave = data_device_handle_leave,\n    .motion = data_device_handle_motion,\n    .drop = data_device_handle_drop,\n    .selection = data_device_handle_selection,\n};\n\nstatic void\nprimary_selection_handle_offer(void *data,\n                               struct zwp_primary_selection_offer_v1 *offer,\n                               const char *mime_type) {}\n\nstatic const struct zwp_primary_selection_offer_v1_listener\n    primary_selection_offer_listener = {\n        .offer = primary_selection_handle_offer,\n};\n\nstatic void primary_selection_device_handle_data_offer(\n    void *data, struct zwp_primary_selection_device_v1 *data_device,\n    struct zwp_primary_selection_offer_v1 *offer) {\n  zwp_primary_selection_offer_v1_add_listener(\n      offer, &primary_selection_offer_listener, NULL);\n}\n\nstatic void primary_selection_device_handle_selection(\n    void *data, struct zwp_primary_selection_device_v1 *data_device,\n    struct zwp_primary_selection_offer_v1 *offer) {\n  clipboard_handle_selection(CLIPBOARD_PRIMARY, offer);\n}\n\nstatic const struct zwp_primary_selection_device_v1_listener\n    primary_selection_device_listener = {\n        .data_offer = primary_selection_device_handle_data_offer,\n        .selection = primary_selection_device_handle_selection,\n};\n\nstatic void wayland_pointer_release(wayland_seat *self) {\n  if (self->pointer == NULL) {\n    return;\n  }\n\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  if (self->cursor_shape_device != NULL) {\n    wp_cursor_shape_device_v1_destroy(self->cursor_shape_device);\n    self->cursor_shape_device = NULL;\n  }\n#endif\n\n  wl_pointer_release(self->pointer);\n\n  self->pointer = NULL;\n}\n\nstatic void wayland_seat_release(wayland_seat *self) {\n  if (self->text_input) {\n    zwp_text_input_v3_destroy(self->text_input);\n    self->text_input = NULL;\n  }\n  wayland_keyboard_release(self);\n  wayland_pointer_release(self);\n\n  wl_seat_release(self->seat);\n\n  g_hash_table_remove(wayland->seats, self->seat);\n\n  g_free(self);\n}\n\nstatic void wayland_seat_capabilities(void *data, struct wl_seat *seat,\n                                      uint32_t capabilities) {\n  wayland_seat *self = data;\n\n  if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) &&\n      (self->keyboard == NULL)) {\n    self->keyboard = wl_seat_get_keyboard(self->seat);\n    wl_keyboard_add_listener(self->keyboard, &wayland_keyboard_listener, self);\n    if (wayland->text_input_manager) {\n      self->text_input = zwp_text_input_manager_v3_get_text_input(\n          wayland->text_input_manager, seat);\n      zwp_text_input_v3_add_listener(self->text_input, &text_input_listener,\n                                     self);\n    }\n  } else if ((!(capabilities & WL_SEAT_CAPABILITY_POINTER)) &&\n             (self->keyboard != NULL)) {\n    wayland_keyboard_release(self);\n  }\n\n  if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && (self->pointer == NULL)) {\n    self->pointer = wl_seat_get_pointer(self->seat);\n    wl_pointer_add_listener(self->pointer, &wayland_pointer_listener, self);\n  } else if ((!(capabilities & WL_SEAT_CAPABILITY_POINTER)) &&\n             (self->pointer != NULL)) {\n    wayland_pointer_release(self);\n  }\n\n  if (wayland->data_device_manager != NULL) {\n    self->data_device = wl_data_device_manager_get_data_device(\n        wayland->data_device_manager, seat);\n    wl_data_device_add_listener(self->data_device, &data_device_listener, NULL);\n  }\n\n  if (wayland->primary_selection_device_manager != NULL) {\n    self->primary_selection_device =\n        zwp_primary_selection_device_manager_v1_get_device(\n            wayland->primary_selection_device_manager, seat);\n    zwp_primary_selection_device_v1_add_listener(\n        self->primary_selection_device, &primary_selection_device_listener,\n        NULL);\n  }\n}\n\nstatic void wayland_seat_name(void *data, struct wl_seat *seat,\n                              const char *name) {\n  wayland_seat *self = data;\n\n  if (self->name != NULL) {\n    g_hash_table_remove(wayland->seats_by_name, self->name);\n  }\n  self->name = g_strdup(name);\n  g_hash_table_insert(wayland->seats_by_name, self->name, self);\n}\n\nstatic const struct wl_seat_listener wayland_seat_listener = {\n    .capabilities = wayland_seat_capabilities,\n    .name = wayland_seat_name,\n};\n\nstatic void update_cursor_rectangle(struct zwp_text_input_v3 *text_input) {\n  textbox *tb = rofi_view_get_active_text();\n  if (tb == NULL) {\n    return;\n  }\n\n  widget *tb_widget = WIDGET(tb);\n  int x = widget_get_x_pos(tb_widget) + textbox_get_cursor_x_pos(tb);\n  int y = widget_get_y_pos(tb_widget);\n  int w = 1;\n  int h = widget_get_height(tb_widget);\n  zwp_text_input_v3_set_cursor_rectangle(text_input, x, y, w, h);\n}\n\nstatic void text_input_enter(void *data, struct zwp_text_input_v3 *text_input,\n                             struct wl_surface *surface) {\n  zwp_text_input_v3_enable(text_input);\n  zwp_text_input_v3_set_content_type(\n      text_input, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,\n      ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);\n  update_cursor_rectangle(text_input);\n  zwp_text_input_v3_commit(text_input);\n}\nstatic void text_input_leave(void *data, struct zwp_text_input_v3 *text_input,\n                             struct wl_surface *surface) {\n  zwp_text_input_v3_disable(text_input);\n  zwp_text_input_v3_commit(text_input);\n}\n\nstatic void text_input_preedit_string(void *data,\n                                      struct zwp_text_input_v3 *text_input,\n                                      const char *text, int32_t cursor_begin,\n                                      int32_t cursor_end) {\n  update_cursor_rectangle(text_input);\n  zwp_text_input_v3_commit(text_input);\n}\n\nstatic void text_input_commit_string(void *data,\n                                     struct zwp_text_input_v3 *text_input,\n                                     const char *text) {\n  if (text == NULL) {\n    return;\n  }\n\n  RofiViewState *state = rofi_view_get_active();\n  if (state) {\n    rofi_view_handle_text(state, text);\n  }\n}\n\nstatic void\ntext_input_delete_surrounding_text(void *data,\n                                   struct zwp_text_input_v3 *text_input,\n                                   uint32_t before_length,\n                                   uint32_t after_length) {}\n\nstatic void text_input_done(void *data, struct zwp_text_input_v3 *text_input,\n                            uint32_t serial) {}\n\nstatic const struct zwp_text_input_v3_listener text_input_listener = {\n    .enter = text_input_enter,\n    .leave = text_input_leave,\n    .preedit_string = text_input_preedit_string,\n    .commit_string = text_input_commit_string,\n    .delete_surrounding_text = text_input_delete_surrounding_text,\n    .done = text_input_done,\n};\n\nstatic void wayland_output_release(wayland_output *self) {\n  g_debug(\"Output release: %s\", self->name);\n\n  if (wl_output_get_version(self->output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) {\n    wl_output_release(self->output);\n  } else {\n    wl_output_destroy(self->output);\n  }\n\n  g_hash_table_remove(wayland->outputs, self->output);\n\n  g_free(self->name);\n  g_free(self);\n}\n\nstatic wayland_output *wayland_output_by_name(const char *name) {\n#ifdef WL_OUTPUT_NAME_SINCE_VERSION\n  GHashTableIter iter;\n  wayland_output *output;\n\n  g_debug(\"Monitor lookup  by name : %s\", name);\n\n  g_hash_table_iter_init(&iter, wayland->outputs);\n  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&output)) {\n    if (g_strcmp0(output->name, name) == 0) {\n      return output;\n    }\n  }\n#endif\n  g_debug(\"Monitor lookup  by name failed: %s\", name);\n\n  return NULL;\n}\ndouble wayland_get_dpi_estimation(void) {\n  double retv = -1.0;\n  if ( wayland == 0 ) {\n    return -1.0;\n  }\n  gsize noutputs = g_hash_table_size(wayland->outputs);\n  if ( noutputs == 1) {\n    GHashTableIter iter;\n    wayland_output *output;\n    g_hash_table_iter_init(&iter, wayland->outputs);\n    if (g_hash_table_iter_next(&iter, NULL, (gpointer *)&output)) {\n      return wayland_output_get_dpi(output, output->current.scale, height);\n    }\n  } else if (noutputs > 1 && config.monitor != NULL ) {\n    wayland_output *output = wayland_output_by_name(config.monitor);\n    if (output != NULL) {\n      return wayland_output_get_dpi(output, output->current.scale, height);\n    }\n  }\n  return retv;\n}\n\nstatic void wayland_output_done(void *data, struct wl_output *output) {\n  wayland_output *self = data;\n\n  self->current = self->pending;\n\n  g_debug(\"Output %s: %\" PRIi32 \"x%\" PRIi32 \" (%\" PRIi32 \"x%\" PRIi32 \"mm)\"\n          \" position %\" PRIi32 \"x%\" PRIi32 \" scale %\" PRIi32\n          \" transform %\" PRIi32,\n          self->name ? self->name : \"Unknown\", self->current.width,\n          self->current.height, self->current.physical_width,\n          self->current.physical_height, self->current.x, self->current.y,\n          self->current.scale, self->current.transform);\n}\n\nstatic void wayland_output_geometry(void *data, struct wl_output *output,\n                                    int32_t x, int32_t y, int32_t width,\n                                    int32_t height, int32_t subpixel,\n                                    const char *make, const char *model,\n                                    int32_t transform) {\n  wayland_output *self = data;\n\n  self->pending.x = x;\n  self->pending.y = y;\n  self->pending.physical_width = width;\n  self->pending.physical_height = height;\n  self->pending.transform = transform;\n}\n\nstatic void wayland_output_mode(void *data, struct wl_output *output,\n                                enum wl_output_mode flags, int32_t width,\n                                int32_t height, int32_t refresh) {\n  if (flags & WL_OUTPUT_MODE_CURRENT) {\n    wayland_output *self = data;\n    self->pending.width = width;\n    self->pending.height = height;\n  }\n}\n\nstatic void wayland_output_scale(void *data, struct wl_output *output,\n                                 int32_t scale) {\n  wayland_output *self = data;\n\n  self->pending.scale = scale;\n}\n\n#ifdef WL_OUTPUT_NAME_SINCE_VERSION\nstatic void wayland_output_name(void *data, struct wl_output *output,\n                                const char *name) {\n  wayland_output *self = data;\n\n  g_free(self->name);\n  self->name = g_strdup(name);\n}\n#endif\n\n#ifdef WL_OUTPUT_DESCRIPTION_SINCE_VERSION\nstatic void wayland_output_description(void *data, struct wl_output *output,\n                                       const char *name) {}\n#endif\n\nstatic const struct wl_output_listener wayland_output_listener = {\n    .geometry = wayland_output_geometry,\n    .mode = wayland_output_mode,\n    .scale = wayland_output_scale,\n    .done = wayland_output_done,\n#ifdef WL_OUTPUT_NAME_SINCE_VERSION\n    .name = wayland_output_name,\n#endif\n#ifdef WL_OUTPUT_DESCRIPTION_SINCE_VERSION\n    .description = wayland_output_description,\n#endif\n};\n\nstatic void wayland_registry_handle_global(void *data,\n                                           struct wl_registry *registry,\n                                           uint32_t name, const char *interface,\n                                           uint32_t version) {\n  g_debug(\"wayland registry: interface %s\", interface);\n\n  if (g_strcmp0(interface, wl_compositor_interface.name) == 0) {\n    wayland->global_names[WAYLAND_GLOBAL_COMPOSITOR] = name;\n    wayland->compositor =\n        wl_registry_bind(registry, name, &wl_compositor_interface,\n                         MIN(version, WL_COMPOSITOR_INTERFACE_VERSION));\n  } else if (g_strcmp0(interface, zwlr_layer_shell_v1_interface.name) == 0) {\n    wayland->global_names[WAYLAND_GLOBAL_LAYER_SHELL] = name;\n    wayland->layer_shell =\n        wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface,\n                         MIN(version, WL_LAYER_SHELL_INTERFACE_VERSION));\n  } else if (g_strcmp0(\n                 interface,\n                 zwp_keyboard_shortcuts_inhibit_manager_v1_interface.name) ==\n             0) {\n    wayland->global_names[WAYLAND_GLOBAL_KEYBOARD_SHORTCUTS_INHIBITOR] = name;\n    wayland->kb_shortcuts_inhibit_manager = wl_registry_bind(\n        registry, name, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface,\n        MIN(version, WL_KEYBOARD_SHORTCUTS_INHIBITOR_INTERFACE_VERSION));\n  } else if (g_strcmp0(interface, wl_shm_interface.name) == 0) {\n    wayland->global_names[WAYLAND_GLOBAL_SHM] = name;\n    wayland->shm = wl_registry_bind(registry, name, &wl_shm_interface,\n                                    MIN(version, WL_SHM_INTERFACE_VERSION));\n  } else if (g_strcmp0(interface, wl_seat_interface.name) == 0) {\n    if (version < WL_SEAT_INTERFACE_MIN_VERSION) {\n      g_error(\"Minimum version of wayland seat interface is %u, got %u\",\n              WL_SEAT_INTERFACE_MIN_VERSION, version);\n      return;\n    }\n    version = MIN(version, WL_SEAT_INTERFACE_MAX_VERSION);\n\n    wayland_seat *seat = g_new0(wayland_seat, 1);\n    seat->context = wayland;\n    seat->global_name = name;\n    seat->seat = wl_registry_bind(registry, name, &wl_seat_interface, version);\n    g_hash_table_insert(wayland->seats, seat->seat, seat);\n\n    wl_seat_add_listener(seat->seat, &wayland_seat_listener, seat);\n  } else if (g_strcmp0(interface, wl_output_interface.name) == 0) {\n    if (version < WL_OUTPUT_INTERFACE_MIN_VERSION) {\n      g_error(\"Minimum version of wayland output interface is %u, got %u\",\n              WL_OUTPUT_INTERFACE_MIN_VERSION, version);\n      return;\n    }\n    version = MIN(version, WL_OUTPUT_INTERFACE_MAX_VERSION);\n\n    wayland_output *output = g_new0(wayland_output, 1);\n    output->context = wayland;\n    output->global_name = name;\n    output->output =\n        wl_registry_bind(registry, name, &wl_output_interface, version);\n    output->pending.scale = 1;\n    output->current = output->pending;\n\n    g_hash_table_insert(wayland->outputs, output->output, output);\n\n    wl_output_add_listener(output->output, &wayland_output_listener, output);\n  } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {\n    wayland->data_device_manager =\n        wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3);\n  } else if (strcmp(interface,\n                    zwp_primary_selection_device_manager_v1_interface.name) ==\n             0) {\n    wayland->primary_selection_device_manager = wl_registry_bind(\n        registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);\n  }\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n  else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {\n    wayland->global_names[WAYLAND_GLOBAL_CURSOR_SHAPE] = name;\n    wayland->cursor_shape_manager = wl_registry_bind(\n        registry, name, &wp_cursor_shape_manager_v1_interface, 1);\n  }\n#endif\n  else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {\n    wayland->text_input_manager = wl_registry_bind(\n        registry, name, &zwp_text_input_manager_v3_interface, 1);\n  }\n}\n\nstatic void wayland_registry_handle_global_remove(void *data,\n                                                  struct wl_registry *registry,\n                                                  uint32_t name) {\n  wayland_global_name i;\n  for (i = 0; i < _WAYLAND_GLOBAL_SIZE; ++i) {\n    if (wayland->global_names[i] != name) {\n      continue;\n    }\n    wayland->global_names[i] = 0;\n\n    switch (i) {\n    case WAYLAND_GLOBAL_COMPOSITOR:\n      wl_compositor_destroy(wayland->compositor);\n      wayland->compositor = NULL;\n      break;\n    case WAYLAND_GLOBAL_CURSOR_SHAPE:\n#ifdef HAVE_WAYLAND_CURSOR_SHAPE\n      wp_cursor_shape_manager_v1_destroy(wayland->cursor_shape_manager);\n      wayland->cursor_shape_manager = NULL;\n#endif\n      break;\n    case WAYLAND_GLOBAL_LAYER_SHELL:\n      zwlr_layer_shell_v1_destroy(wayland->layer_shell);\n      wayland->layer_shell = NULL;\n      break;\n    case WAYLAND_GLOBAL_KEYBOARD_SHORTCUTS_INHIBITOR:\n      zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(\n          wayland->kb_shortcuts_inhibit_manager);\n      wayland->kb_shortcuts_inhibit_manager = NULL;\n      break;\n    case WAYLAND_GLOBAL_SHM:\n      wl_shm_destroy(wayland->shm);\n      wayland->shm = NULL;\n      break;\n    case _WAYLAND_GLOBAL_SIZE:\n      g_assert_not_reached();\n    }\n    return;\n  }\n  if ((wayland->cursor.theme != NULL) &&\n      ((wayland->compositor == NULL) || (wayland->shm == NULL))) {\n    if (wayland->cursor.frame_cb != NULL) {\n      wl_callback_destroy(wayland->cursor.frame_cb);\n      wayland->cursor.frame_cb = NULL;\n    }\n\n    wl_surface_destroy(wayland->cursor.surface);\n    wl_cursor_theme_destroy(wayland->cursor.theme);\n    wayland->cursor.surface = NULL;\n    wayland->cursor.image = NULL;\n    wayland->cursor.cursor = NULL;\n    wayland->cursor.theme = NULL;\n    wayland->cursor.scale = 0;\n  }\n\n  GHashTableIter iter;\n\n  wayland_seat *seat;\n  g_hash_table_iter_init(&iter, wayland->seats);\n  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&seat)) {\n    if (seat->global_name != name) {\n      continue;\n    }\n\n    g_hash_table_iter_remove(&iter);\n    wayland_seat_release(seat);\n    return;\n  }\n\n  wayland_output *output;\n  g_hash_table_iter_init(&iter, wayland->outputs);\n  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&output)) {\n    if (output->global_name != name) {\n      continue;\n    }\n\n    g_hash_table_iter_remove(&iter);\n    wayland_output_release(output);\n    return;\n  }\n}\n\nstatic const struct wl_registry_listener wayland_registry_listener = {\n    .global = wayland_registry_handle_global,\n    .global_remove = wayland_registry_handle_global_remove,\n};\n\nstatic void wayland_layer_shell_surface_configure(\n    void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial,\n    uint32_t width, uint32_t height) {\n  wayland->layer_width = width;\n  wayland->layer_height = height;\n  zwlr_layer_surface_v1_ack_configure(surface, serial);\n}\n\nstatic void wayland_surface_destroy(void) {\n  if (wayland->wlr_surface != NULL) {\n    zwlr_layer_surface_v1_destroy(wayland->wlr_surface);\n    wayland->wlr_surface = NULL;\n  }\n  if (wayland->surface != NULL) {\n    wl_surface_destroy(wayland->surface);\n    wayland->surface = NULL;\n  }\n}\n\nstatic void\nwayland_layer_shell_surface_closed(void *data,\n                                   struct zwlr_layer_surface_v1 *surface) {\n  g_debug(\"Layer shell surface closed\");\n\n  wayland_surface_destroy();\n\n  // In this case, we recreate the layer shell surface the best we can and\n  // re-initialize everything:\n\n  // recreate layer shell\n  wayland_display_late_setup();\n\n  // create new buffers with the correct scaled size\n  rofi_view_pool_refresh();\n\n  RofiViewState *state = rofi_view_get_active();\n  if (state != NULL) {\n    rofi_view_set_size(state, -1, -1);\n  }\n}\n\nstatic const struct zwlr_layer_surface_v1_listener\n    wayland_layer_shell_surface_listener = {\n        .configure = wayland_layer_shell_surface_configure,\n        .closed = wayland_layer_shell_surface_closed,\n};\n\nstatic gboolean wayland_error(gpointer user_data) {\n  g_main_loop_quit(wayland->main_loop);\n  return G_SOURCE_REMOVE;\n}\n\nstatic gboolean wayland_cursor_reload_theme(guint scale) {\n  if (wayland->cursor.theme != NULL) {\n    if (wayland->cursor.scale == scale)\n      return TRUE;\n\n    wl_cursor_theme_destroy(wayland->cursor.theme);\n    wayland->cursor.theme = NULL;\n    wayland->cursor.cursor = NULL;\n  }\n\n  guint64 cursor_size = 24;\n  char *env_cursor_size = (char *)g_getenv(\"XCURSOR_SIZE\");\n  if (env_cursor_size && strlen(env_cursor_size) > 0) {\n    guint64 size = g_ascii_strtoull(env_cursor_size, NULL, 10);\n    if (0 < size && size < G_MAXUINT64) {\n      cursor_size = size;\n    }\n  }\n  cursor_size *= scale;\n\n  wayland->cursor.theme = wl_cursor_theme_load(wayland->cursor.theme_name,\n                                               cursor_size, wayland->shm);\n  if (wayland->cursor.theme != NULL) {\n    wayland->cursor.cursor = rofi_cursor_type_to_wl_cursor(\n        wayland->cursor.theme, wayland->cursor.type);\n    if (wayland->cursor.cursor == NULL) {\n      wl_cursor_theme_destroy(wayland->cursor.theme);\n      wayland->cursor.theme = NULL;\n      return FALSE;\n    } else {\n      wayland->cursor.scale = scale;\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n\nstatic gboolean wayland_display_setup(GMainLoop *main_loop,\n                                      NkBindings *bindings) {\n  wayland->main_loop = main_loop;\n\n  char *display = (char *)g_getenv(\"WAYLAND_DISPLAY\");\n  wayland->main_loop_source = g_water_wayland_source_new(NULL, display);\n  if (wayland->main_loop_source == NULL) {\n    g_warning(\"Could not connect to the Wayland compositor\");\n    return FALSE;\n  }\n\n  g_water_wayland_source_set_error_callback(wayland->main_loop_source,\n                                            wayland_error, NULL, NULL);\n\n  wayland->buffer_count = 3;\n  wayland->cursor.type = ROFI_CURSOR_DEFAULT;\n  wayland->scale = 1;\n\n  wayland->outputs = g_hash_table_new(g_direct_hash, g_direct_equal);\n  wayland->seats = g_hash_table_new(g_direct_hash, g_direct_equal);\n  wayland->seats_by_name =\n      g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);\n\n  wayland->display =\n      g_water_wayland_source_get_display(wayland->main_loop_source);\n  wayland->registry = wl_display_get_registry(wayland->display);\n  wl_registry_add_listener(wayland->registry, &wayland_registry_listener, NULL);\n  wl_display_roundtrip(wayland->display);\n\n  if (wayland->compositor == NULL || wayland->shm == NULL ||\n      g_hash_table_size(wayland->outputs) == 0 ||\n      g_hash_table_size(wayland->seats) == 0) {\n    g_error(\"Could not connect to wayland compositor\");\n    return FALSE;\n  }\n  if (wayland->layer_shell == NULL) {\n    g_error(\"Rofi on wayland requires support for the layer shell protocol\");\n    return FALSE;\n  }\n\n  wayland->bindings_seat = nk_bindings_seat_new(bindings, XKB_CONTEXT_NO_FLAGS);\n\n  // Wait for output information\n  wl_display_roundtrip(wayland->display);\n\n  return TRUE;\n}\n\nstatic gboolean wayland_display_late_setup(void) {\n  wayland_output *output = wayland_output_by_name(config.monitor);\n\n  struct wl_output *wlo = NULL;\n  if (output != NULL) {\n    wlo = output->output;\n  }\n  wayland->surface = wl_compositor_create_surface(wayland->compositor);\n\n  uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;\n  if (strcmp(config.wayland_layer, \"overlay\") == 0) {\n    layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;\n  } else if (strcmp(config.wayland_layer, \"top\") == 0) {\n    layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP;\n  } else if (strcmp(config.wayland_layer, \"bottom\") == 0) {\n    layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;\n  } else if (strcmp(config.wayland_layer, \"background\") == 0) {\n    layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;\n  } else {\n    layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;\n    g_warning(\"Unknown wayland layer: %s, using default overlay\", config.wayland_layer);\n  }\n  wayland->wlr_surface = zwlr_layer_shell_v1_get_layer_surface(\n      wayland->layer_shell, wayland->surface, wlo, layer, \"rofi\");\n\n  // Set size zero and anchor on all corners to get the usable screen size\n  // see https://github.com/swaywm/wlroots/pull/2422\n  zwlr_layer_surface_v1_set_anchor(wayland->wlr_surface,\n                                   ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |\n                                       ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |\n                                       ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |\n                                       ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);\n  zwlr_layer_surface_v1_set_size(wayland->wlr_surface, 0, 0);\n  zwlr_layer_surface_v1_set_keyboard_interactivity(wayland->wlr_surface, 1);\n  zwlr_layer_surface_v1_add_listener(\n      wayland->wlr_surface, &wayland_layer_shell_surface_listener, NULL);\n\n  if (config.global_kb && wayland->kb_shortcuts_inhibit_manager) {\n    g_debug(\"inhibit shortcuts from compositor\");\n    GHashTableIter iter;\n    wayland_seat *seat;\n    g_hash_table_iter_init(&iter, wayland->seats);\n    while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&seat)) {\n      // we don't need to keep track of these, they will get inactive when the\n      // surface is destroyed\n      zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(\n          wayland->kb_shortcuts_inhibit_manager, wayland->surface, seat->seat);\n    }\n  }\n\n  wl_surface_add_listener(wayland->surface, &wayland_surface_interface,\n                          wayland);\n  wl_surface_commit(wayland->surface);\n  wl_display_roundtrip(wayland->display);\n  wayland_frame_callback(wayland, wayland->frame_cb, 0);\n\n  return TRUE;\n}\n\ngboolean display_get_surface_dimensions(int *width, int *height) {\n  if (wayland->layer_width != 0) {\n    if (width != NULL) {\n      *width = wayland->layer_width;\n    }\n    if (height != NULL) {\n      *height = wayland->layer_height;\n    }\n    return TRUE;\n  }\n  return FALSE;\n}\n\nvoid display_set_surface_dimensions(int width, int height, int x_margin,\n                                    int y_margin, int loc) {\n\n  wayland->layer_width = width;\n  wayland->layer_height = height;\n  zwlr_layer_surface_v1_set_size(wayland->wlr_surface, width, height);\n\n  uint32_t wlr_anchor = 0;\n  switch (loc) {\n  case WL_NORTH_WEST:\n    wlr_anchor =\n        ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;\n    break;\n  case WL_NORTH:\n    wlr_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;\n    break;\n  case WL_NORTH_EAST:\n    wlr_anchor =\n        ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;\n    break;\n  case WL_EAST:\n    wlr_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;\n    break;\n  case WL_SOUTH_EAST:\n    wlr_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |\n                 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;\n    break;\n  case WL_SOUTH:\n    wlr_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;\n    break;\n  case WL_SOUTH_WEST:\n    wlr_anchor =\n        ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;\n    break;\n  case WL_WEST:\n    wlr_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;\n    break;\n  case WL_CENTER:\n  default:\n    break;\n  }\n\n  if (height == 0) {\n    wlr_anchor |=\n        ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;\n  }\n  if (width == 0) {\n    wlr_anchor |=\n        ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;\n  }\n\n  zwlr_layer_surface_v1_set_anchor(wayland->wlr_surface, wlr_anchor);\n\n  // NOTE: Setting margin for edges we are not anchored to has no effect, so\n  // we can safely set contradictory margins (e.g. top vs bottom) - at most\n  // one of the margins on a given axis will have effect. This also means that\n  // margin has no effect if the window is centered. :(\n  zwlr_layer_surface_v1_set_margin(wayland->wlr_surface, y_margin, -x_margin,\n                                   -y_margin, x_margin);\n}\n\nstatic void wayland_display_early_cleanup(void) {\n  if (wayland->main_loop_source == NULL) {\n    return;\n  }\n\n  wayland_surface_destroy();\n  wl_display_flush(wayland->display);\n}\n\nstatic void wayland_display_cleanup(void) {\n  if (wayland->main_loop_source == NULL) {\n    return;\n  }\n\n  nk_bindings_seat_free(wayland->bindings_seat);\n  g_hash_table_unref(wayland->seats_by_name);\n  g_hash_table_unref(wayland->seats);\n  g_hash_table_unref(wayland->outputs);\n  wl_registry_destroy(wayland->registry);\n  wl_display_flush(wayland->display);\n  g_water_wayland_source_free(wayland->main_loop_source);\n}\n\nstatic void wayland_display_dump_monitor_layout(void) {\n  int is_term = isatty(fileno(stdout));\n  GHashTableIter iter;\n  wayland_output *output;\n\n  g_hash_table_iter_init(&iter, wayland->outputs);\n  printf(\"Monitor layout:\\n\");\n  while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&output)) {\n    printf(\"%s              ID%s: %\" PRIu32, is_term ? color_bold : \"\",\n           is_term ? color_reset : \"\", output->global_name);\n    printf(\"\\n\");\n    printf(\"%s            name%s: %s\\n\", is_term ? color_bold : \"\",\n           is_term ? color_reset : \"\", output->name);\n    printf(\"%s           scale%s: %\" PRIi32 \"\\n\", is_term ? color_bold : \"\",\n           is_term ? color_reset : \"\", output->current.scale);\n    printf(\"%s        position%s: %\" PRIi32 \",%\" PRIi32 \"\\n\",\n           is_term ? color_bold : \"\", is_term ? color_reset : \"\",\n           output->current.x, output->current.y);\n    printf(\"%s            size%s: %\" PRIi32 \",%\" PRIi32 \"\\n\",\n           is_term ? color_bold : \"\", is_term ? color_reset : \"\",\n           output->current.width, output->current.height);\n\n    if (output->current.physical_width > 0 &&\n        output->current.physical_height > 0) {\n      printf(\"%s            size%s: %\" PRIi32 \"mm,%\" PRIi32\n             \"mm  dpi: %.0f,%.0f\\n\",\n             is_term ? color_bold : \"\", is_term ? color_reset : \"\",\n             output->current.physical_width, output->current.physical_height,\n             wayland_output_get_dpi(output, output->current.scale, width),\n             wayland_output_get_dpi(output, output->current.scale, height));\n    }\n    printf(\"\\n\");\n  }\n}\n\nstatic void\nwayland_display_startup_notification(RofiHelperExecuteContext *context,\n                                     GSpawnChildSetupFunc *child_setup,\n                                     gpointer *user_data) {}\n\nstatic int wayland_display_monitor_active(workarea *mon) {\n  // TODO: do something?\n  return FALSE;\n}\n\nstatic void wayland_display_set_input_focus(guint w) {}\n\nstatic void wayland_display_revert_input_focus(void) {}\n\nstatic const struct _view_proxy *wayland_display_view_proxy(void) {\n  return wayland_view_proxy;\n}\n\nstatic guint wayland_display_scale(void) { return wayland->scale; }\n\nstatic void wayland_get_clipboard_data(int cb_type, ClipboardCb callback,\n                                       void *user_data) {\n  clipboard_data *clipboard = &wayland->clipboards[cb_type];\n\n  if (clipboard->offer == NULL) {\n    return;\n  }\n\n  int fds[2];\n  if (pipe(fds) < 0) {\n    return;\n  }\n\n  if (cb_type == CLIPBOARD_DEFAULT) {\n    wl_data_offer_receive(clipboard->offer, \"text/plain;charset=utf-8\", fds[1]);\n  } else {\n    zwp_primary_selection_offer_v1_receive(clipboard->offer, \"text/plain;charset=utf-8\",\n                                           fds[1]);\n  }\n  close(fds[1]);\n\n  clipboard_read_data(fds[0], callback, user_data);\n}\n\nstatic void wayland_set_fullscreen_mode(void) {\n  if (!wayland->wlr_surface) {\n    return;\n  }\n  zwlr_layer_surface_v1_set_exclusive_zone(wayland->wlr_surface, -1);\n  zwlr_layer_surface_v1_set_size(wayland->wlr_surface, 0, 0);\n  wl_surface_commit(wayland->surface);\n  wl_display_roundtrip(wayland->display);\n\n  rofi_view_pool_refresh();\n}\n\nstatic display_proxy display_ = {\n    .setup = wayland_display_setup,\n    .late_setup = wayland_display_late_setup,\n    .early_cleanup = wayland_display_early_cleanup,\n    .cleanup = wayland_display_cleanup,\n    .dump_monitor_layout = wayland_display_dump_monitor_layout,\n    .startup_notification = wayland_display_startup_notification,\n    .monitor_active = wayland_display_monitor_active,\n    .set_input_focus = wayland_display_set_input_focus,\n    .revert_input_focus = wayland_display_revert_input_focus,\n    .scale = wayland_display_scale,\n    .get_clipboard_data = wayland_get_clipboard_data,\n    .set_fullscreen_mode = wayland_set_fullscreen_mode,\n\n    .view = wayland_display_view_proxy,\n};\n\ndisplay_proxy *const wayland_proxy = &display_;\n"
  },
  {
    "path": "source/wayland/view.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The Rofi View log domain */\n#define G_LOG_DOMAIN \"View\"\n\n#include <config.h>\n#include <errno.h>\n#include <locale.h>\n#include <signal.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include <cairo.h>\n\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"timings.h\"\n\n#include \"display.h\"\n#include \"helper-theme.h\"\n#include \"helper.h\"\n#include \"mode.h\"\n#include \"modes/modes.h\"\n\n#include \"view-internal.h\"\n#include \"view.h\"\n\n#include \"theme.h\"\n\n/**\n * @param state The handle to the view\n * @param qr    Indicate if queue_redraw should be called on changes.\n *\n * Update the state of the view. This involves filter state.\n */\nstatic void wayland_rofi_view_update(RofiViewState *state, gboolean qr);\n\n/**\n * Structure holding some state\n */\nstatic struct {\n  /** Main flags */\n  MenuFlags flags;\n  /** timeout for reloading */\n  guint idle_timeout;\n  /** debug counter for redraws */\n  unsigned long long count;\n  /** redraw idle time. */\n  guint repaint_source;\n  /** Window fullscreen */\n  gboolean fullscreen;\n\n  int monitor_width;\n  int monitor_height;\n} WlState = {\n    .flags = MENU_NORMAL,\n    .idle_timeout = 0,\n    .count = 0L,\n    .repaint_source = 0,\n    .fullscreen = FALSE,\n    .monitor_width = 0,\n    .monitor_height = 0,\n};\n\nstatic void wayland_rofi_view_get_current_monitor(int *width, int *height) {\n  // TODO: handle changing monitor resolution\n  if (WlState.monitor_width == 0 && WlState.monitor_height == 0) {\n    display_get_surface_dimensions(&WlState.monitor_width,\n                                   &WlState.monitor_height);\n  }\n\n  if (width) {\n    *width = WlState.monitor_width;\n  }\n  if (height) {\n    *height = WlState.monitor_height;\n  }\n}\n\nstatic gboolean wayland_rofi_view_repaint(G_GNUC_UNUSED void *data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state) {\n    // Repaint the view (if needed).\n    // After a resize the edit_pixmap surface might not contain anything\n    // anymore. If we already re-painted, this does nothing.\n    rofi_view_maybe_update(state);\n    WlState.repaint_source = 0;\n  }\n  return G_SOURCE_REMOVE;\n}\n\nstatic const int loc_transtable[9] = {\n    WL_CENTER, WL_NORTH | WL_WEST, WL_NORTH, WL_NORTH | WL_EAST,\n    WL_EAST,   WL_SOUTH | WL_EAST, WL_SOUTH, WL_SOUTH | WL_WEST,\n    WL_WEST};\n\nstatic void wayland_rofi_view_calculate_window_position(\n    G_GNUC_UNUSED RofiViewState *state) {}\n\nstatic int rofi_get_location(RofiViewState *state) {\n  return rofi_theme_get_position(WIDGET(state->main_window), \"location\",\n                                 loc_transtable[config.location]);\n}\n\nstatic int rofi_get_offset_px(RofiViewState *state, RofiOrientation ori) {\n  char *property = ori == ROFI_ORIENTATION_HORIZONTAL ? \"x-offset\" : \"y-offset\";\n\n  RofiDistance offset =\n      rofi_theme_get_distance(WIDGET(state->main_window), property, 0);\n  return distance_get_pixel(offset, ori);\n}\n\nstatic void wayland_rofi_view_window_update_size(RofiViewState *state) {\n  if (state == NULL) {\n    return;\n  }\n  int offset_x = rofi_get_offset_px(state, ROFI_ORIENTATION_HORIZONTAL);\n  int offset_y = rofi_get_offset_px(state, ROFI_ORIENTATION_VERTICAL);\n\n  widget_resize(WIDGET(state->main_window), state->width, state->height);\n  display_set_surface_dimensions(state->width, state->height, offset_x,\n                                 offset_y, rofi_get_location(state));\n  rofi_view_pool_refresh();\n}\n\nstatic void wayland_rofi_view_set_size(RofiViewState *state, gint width,\n                                       gint height) {\n  if (width > -1) {\n    state->width = width;\n  }\n  if (height > -1) {\n    state->height = height;\n  }\n  wayland_rofi_view_window_update_size(state);\n}\n\nstatic void wayland_rofi_view_get_size(RofiViewState *state, gint *width,\n                                       gint *height) {\n  *width = state->width;\n  *height = state->height;\n}\n\nstatic void wayland_rofi_view_ping_mouse(RofiViewState *state) { (void)state; }\n\nstatic gboolean wayland_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {\n  RofiViewState *state = rofi_view_get_active();\n\n  if (state) {\n    // For UI update on this.\n    if (state->tb_total_rows) {\n      char *r = g_strdup_printf(\"%u\", mode_get_num_entries(state->sw));\n      textbox_text(state->tb_total_rows, r);\n      g_free(r);\n    }\n    state->reload = TRUE;\n    state->refilter = TRUE;\n\n    rofi_view_maybe_update(state);\n  }\n  WlState.idle_timeout = 0;\n  return G_SOURCE_REMOVE;\n}\n\nstatic void wayland_rofi_view_reload(void) {\n  // @TODO add check if current view is equal to the callee\n  if (WlState.idle_timeout == 0) {\n    WlState.idle_timeout =\n        g_timeout_add(1000 / 15, wayland_rofi_view_reload_idle, NULL);\n  }\n}\nstatic void wayland_rofi_view_queue_redraw(void) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state && WlState.repaint_source == 0) {\n    WlState.count++;\n    g_debug(\"redraw %llu\", WlState.count);\n\n    widget_queue_redraw(WIDGET(state->main_window));\n\n    WlState.repaint_source = g_idle_add_full(\n        G_PRIORITY_HIGH_IDLE, wayland_rofi_view_repaint, NULL, NULL);\n  }\n}\n\nstatic void wayland___create_window(MenuFlags menu_flags) {\n  input_history_initialize();\n\n  TICK_N(\"create cairo surface\");\n  // TODO should we update the drawable each time?\n  PangoContext *p = pango_context_new();\n  pango_context_set_font_map(p, pango_cairo_font_map_get_default());\n  TICK_N(\"pango cairo font setup\");\n\n  WlState.flags = menu_flags;\n  // Setup dpi\n  PangoFontMap *font_map = pango_cairo_font_map_get_default();\n  if (config.dpi > 1) {\n    pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,\n                                        (double)config.dpi);\n  } else if (config.dpi == 0 || config.dpi == 1) {\n    // This is an heuristic that works well for simple cases (eg single monitor)\n    // Accurate dpi information only comes after we display the first surface on\n    // the screen when it's too late to use for metric units.\n    double dpi = wayland_get_dpi_estimation();\n    if (dpi >= 0) {\n      config.dpi = dpi;\n      pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);\n    } else {\n      g_warning(\n          \"DPI auto-detect failed, the output is not known yet or does not \"\n          \"provide a physical size\");\n      config.dpi =\n          pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);\n    }\n  } else {\n    // default pango is 96.\n    config.dpi =\n        pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);\n  }\n  // Setup font.\n  // Dummy widget.\n  box *win = box_create(NULL, \"window\", ROFI_ORIENTATION_HORIZONTAL);\n  const char *font =\n      rofi_theme_get_string(WIDGET(win), \"font\", config.menu_font);\n  if (font) {\n    PangoFontDescription *pfd = pango_font_description_from_string(font);\n    if (helper_validate_font(pfd, font)) {\n      pango_context_set_font_description(p, pfd);\n    }\n    pango_font_description_free(pfd);\n  }\n  PangoLanguage *l = pango_language_get_default();\n  pango_context_set_language(p, l);\n  TICK_N(\"configure font\");\n\n  // Tell textbox to use this context.\n  textbox_set_pango_context(font, p);\n  // cleanup\n  g_object_unref(p);\n\n  WlState.fullscreen = rofi_theme_get_boolean(WIDGET(win), \"fullscreen\", FALSE);\n\n  if (WlState.fullscreen) {\n    display_set_fullscreen_mode();\n  }\n\n  widget_free(WIDGET(win));\n\n  TICK_N(\"done\");\n}\n\n/**\n * @param state Internal state of the menu.\n *\n * Calculate the width of the window and the width of an element.\n */\nstatic void wayland_rofi_view_calculate_window_width(RofiViewState *state) {\n  int screen_width = 1920;\n  display_get_surface_dimensions(&screen_width, NULL);\n\n  if (WlState.fullscreen == TRUE) {\n    state->width = screen_width;\n    return;\n  }\n\n  // Calculate as float to stop silly, big rounding down errors.\n  state->width = (screen_width / 100.0f) * DEFAULT_MENU_WIDTH;\n  // Use theme configured width, if set.\n  RofiDistance width = rofi_theme_get_distance(WIDGET(state->main_window),\n                                               \"width\", state->width);\n  state->width = distance_get_pixel(width, ROFI_ORIENTATION_HORIZONTAL);\n}\n\nstatic void wayland_rofi_view_update(RofiViewState *state, gboolean qr) {\n  if (!widget_need_redraw(WIDGET(state->main_window))) {\n    return;\n  }\n  g_debug(\"Redraw view\");\n  TICK();\n  if (state->pool == NULL) {\n    state->pool = display_buffer_pool_new(state->width, state->height);\n  }\n  cairo_surface_t *surface = display_buffer_pool_get_next_buffer(state->pool);\n  if (surface == NULL) {\n    // no available buffer, bail out\n    return;\n  }\n  cairo_t *d = cairo_create(surface);\n  cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);\n  // Paint the background transparent.\n  cairo_set_source_rgba(d, 0, 0, 0, 0.0);\n  guint scale = display_scale();\n  cairo_surface_set_device_scale(surface, scale, scale);\n  cairo_paint(d);\n  TICK_N(\"Background\");\n\n  // Always paint as overlay over the background.\n  cairo_set_operator(d, CAIRO_OPERATOR_OVER);\n  widget_draw(WIDGET(state->main_window), d);\n\n  TICK_N(\"widgets\");\n  cairo_destroy(d);\n  display_surface_commit(surface);\n\n  if (qr) {\n    wayland_rofi_view_queue_redraw();\n  }\n}\n\n/**\n * @param state The Menu Handle\n *\n * Check if a finalize function is set, and if sets executes it.\n */\nvoid process_result(RofiViewState *state);\n\nstatic void wayland_rofi_view_frame_callback(void) {\n  if (WlState.repaint_source == 0) {\n    WlState.repaint_source = g_idle_add_full(\n        G_PRIORITY_HIGH_IDLE, wayland_rofi_view_repaint, NULL, NULL);\n  }\n}\n\nstatic int wayland_rofi_view_calculate_window_height(RofiViewState *state) {\n  if (WlState.fullscreen == TRUE) {\n    int height = 1080;\n    display_get_surface_dimensions(NULL, &height);\n    return height;\n  }\n\n  RofiDistance h =\n      rofi_theme_get_distance(WIDGET(state->main_window), \"height\", 0);\n  unsigned int height = distance_get_pixel(h, ROFI_ORIENTATION_VERTICAL);\n  // If height is set, return it.\n  if (height > 0) {\n    return height;\n  }\n  // Autosize based on widgets.\n  widget *main_window = WIDGET(state->main_window);\n\n  return widget_get_desired_height(main_window, state->width);\n}\n\nstatic void wayland_rofi_view_hide(void) { display_early_cleanup(); }\n\nstatic void wayland_rofi_view_cleanup(void) {\n  g_debug(\"Cleanup.\");\n  if (WlState.idle_timeout > 0) {\n    g_source_remove(WlState.idle_timeout);\n    WlState.idle_timeout = 0;\n  }\n  if (CacheState.refilter_timeout > 0) {\n    g_source_remove(CacheState.refilter_timeout);\n    CacheState.refilter_timeout = 0;\n  }\n  if (CacheState.overlay_timeout) {\n    g_source_remove(CacheState.overlay_timeout);\n    CacheState.overlay_timeout = 0;\n  }\n  if (CacheState.user_timeout > 0) {\n    g_source_remove(CacheState.user_timeout);\n    CacheState.user_timeout = 0;\n  }\n  if (WlState.repaint_source > 0) {\n    g_source_remove(WlState.repaint_source);\n    WlState.repaint_source = 0;\n  }\n\n  input_history_save();\n}\n\nstatic void\nwayland_rofi_view_set_window_title(G_GNUC_UNUSED const char *title) {}\n\nstatic void wayland_rofi_view_pool_refresh(void) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return;\n  }\n  display_buffer_pool_free(state->pool);\n  state->pool = NULL;\n  wayland_rofi_view_update(state, TRUE);\n}\n\nstatic view_proxy view_ = {\n    .update = wayland_rofi_view_update,\n    .temp_configure_notify = NULL,\n    .temp_click_to_exit = NULL,\n    .frame_callback = wayland_rofi_view_frame_callback,\n    .queue_redraw = wayland_rofi_view_queue_redraw,\n\n    .set_window_title = wayland_rofi_view_set_window_title,\n    .calculate_window_position = wayland_rofi_view_calculate_window_position,\n    .calculate_window_height = wayland_rofi_view_calculate_window_height,\n    .calculate_window_width = wayland_rofi_view_calculate_window_width,\n    .window_update_size = wayland_rofi_view_window_update_size,\n    .set_cursor = wayland_display_set_cursor_type,\n    .ping_mouse = wayland_rofi_view_ping_mouse,\n\n    .cleanup = wayland_rofi_view_cleanup,\n    .hide = wayland_rofi_view_hide,\n    .reload = wayland_rofi_view_reload,\n\n    .__create_window = wayland___create_window,\n    .get_window = NULL,\n    .get_current_monitor = wayland_rofi_view_get_current_monitor,\n\n    .set_size = wayland_rofi_view_set_size,\n    .get_size = wayland_rofi_view_get_size,\n\n    .pool_refresh = wayland_rofi_view_pool_refresh,\n};\n\nconst view_proxy *wayland_view_proxy = &view_;\n"
  },
  {
    "path": "source/widgets/box.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this widget. */\n#define G_LOG_DOMAIN \"Widgets.Box\"\n\n#include \"widgets/box.h\"\n#include \"theme.h\"\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <stdio.h>\n\n/** Default spacing used in the box*/\n#define DEFAULT_SPACING 2\n\nstruct _box {\n  widget widget;\n  RofiOrientation type;\n  int max_size;\n  // RofiPadding between elements\n  RofiDistance spacing;\n\n  GList *children;\n};\n\nstatic void box_update(widget *wid);\n\nstatic int box_get_desired_width(widget *wid, const int height) {\n  box *b = (box *)wid;\n  int spacing = distance_get_pixel(b->spacing, b->type);\n  int width = 0;\n\n  // Allow user to override.\n  RofiDistance w = rofi_theme_get_distance(wid, \"width\", 0);\n  width = distance_get_pixel(w, ROFI_ORIENTATION_HORIZONTAL);\n  if (width > 0) {\n    return width;\n  }\n\n  if (b->type == ROFI_ORIENTATION_HORIZONTAL) {\n    int active_widgets = 0;\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (!child->enabled) {\n        continue;\n      }\n      active_widgets++;\n      if (child->expand == TRUE) {\n        width += widget_get_desired_width(child, height);\n        continue;\n      }\n      width += widget_get_desired_width(child, height);\n    }\n    if (active_widgets > 0) {\n      width += (active_widgets - 1) * spacing;\n    }\n  } else {\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (!child->enabled) {\n        continue;\n      }\n      width = MAX(widget_get_desired_width(child, height), width);\n    }\n  }\n  width += widget_padding_get_padding_width(wid);\n  return width;\n}\nstatic int box_get_desired_height(widget *wid, const int width) {\n  box *b = (box *)wid;\n  int spacing = distance_get_pixel(b->spacing, b->type);\n  int height = 0;\n  int nw = width - widget_padding_get_padding_width(wid);\n  if (b->type == ROFI_ORIENTATION_VERTICAL) {\n    int active_widgets = 0;\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (!child->enabled) {\n        continue;\n      }\n      active_widgets++;\n      height += widget_get_desired_height(child, nw);\n    }\n    if (active_widgets > 0) {\n      height += (active_widgets - 1) * spacing;\n    }\n  } else {\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (!child->enabled) {\n        continue;\n      }\n      height = MAX(widget_get_desired_height(child, nw), height);\n    }\n  }\n  height += widget_padding_get_padding_height(wid);\n  return height;\n}\n\nstatic void vert_calculate_size(box *b) {\n  int spacing = distance_get_pixel(b->spacing, ROFI_ORIENTATION_VERTICAL);\n  int expanding_widgets = 0;\n  int active_widgets = 0;\n  int rem_width = widget_padding_get_remaining_width(WIDGET(b));\n  int rem_height = widget_padding_get_remaining_height(WIDGET(b));\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    if (child->enabled && child->expand == FALSE) {\n      widget_resize(child, rem_width,\n                    widget_get_desired_height(child, rem_width));\n    }\n  }\n  b->max_size = 0;\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    if (!child->enabled) {\n      continue;\n    }\n    active_widgets++;\n    if (child->expand == TRUE) {\n      expanding_widgets++;\n      continue;\n    }\n    if (child->h > 0) {\n      b->max_size += child->h;\n    }\n  }\n  if (active_widgets > 0) {\n    b->max_size += (active_widgets - 1) * spacing;\n  }\n  if (b->max_size > rem_height) {\n    b->max_size = rem_height;\n    g_debug(\"Widgets to large (height) for box: %d %d\", b->max_size,\n            b->widget.h);\n    return;\n  }\n  if (active_widgets > 0) {\n    int top = widget_padding_get_top(WIDGET(b));\n    double rem = rem_height - b->max_size;\n    int index = 0;\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (child->enabled == FALSE) {\n        continue;\n      }\n      if (child->expand == TRUE) {\n        // Re-calculate to avoid round issues leaving one pixel left.\n        int expanding_widgets_size = (rem) / (expanding_widgets - index);\n        widget_move(child, widget_padding_get_left(WIDGET(b)), top);\n        top += expanding_widgets_size;\n        widget_resize(child, rem_width, expanding_widgets_size);\n        top += spacing;\n        rem -= expanding_widgets_size;\n        index++;\n      } else {\n        widget_move(child, widget_padding_get_left(WIDGET(b)), top);\n        top += widget_get_height(child);\n        top += spacing;\n      }\n    }\n  }\n  b->max_size += widget_padding_get_padding_height(WIDGET(b));\n}\nstatic void hori_calculate_size(box *b) {\n  int spacing = distance_get_pixel(b->spacing, ROFI_ORIENTATION_HORIZONTAL);\n  int expanding_widgets = 0;\n  int active_widgets = 0;\n  int rem_width = widget_padding_get_remaining_width(WIDGET(b));\n  int rem_height = widget_padding_get_remaining_height(WIDGET(b));\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    if (child->enabled && child->expand == FALSE) {\n      widget_resize(child,\n                    widget_get_desired_width(child, rem_height), // child->w,\n                    rem_height);\n    }\n  }\n  b->max_size = 0;\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    if (!child->enabled) {\n      continue;\n    }\n    active_widgets++;\n    if (child->expand == TRUE) {\n      expanding_widgets++;\n      continue;\n    }\n    // Size used by fixed width widgets.\n    if (child->h > 0) {\n      b->max_size += child->w;\n    }\n  }\n  b->max_size += MAX(0, ((active_widgets - 1) * spacing));\n  if (b->max_size > (rem_width)) {\n    b->max_size = rem_width;\n    g_debug(\"Widgets to large (width) for box: %d %d\", b->max_size,\n            b->widget.w);\n    // return;\n  }\n  if (active_widgets > 0) {\n    int left = widget_padding_get_left(WIDGET(b));\n    double rem = rem_width - b->max_size;\n    int index = 0;\n    if (rem < 0) {\n      rem = 0;\n    }\n    for (GList *iter = g_list_first(b->children); iter != NULL;\n         iter = g_list_next(iter)) {\n      widget *child = (widget *)iter->data;\n      if (child->enabled == FALSE) {\n        continue;\n      }\n      if (child->expand == TRUE) {\n        // Re-calculate to avoid round issues leaving one pixel left.\n        int expanding_widgets_size = (rem) / (expanding_widgets - index);\n        widget_move(child, left, widget_padding_get_top(WIDGET(b)));\n        left += expanding_widgets_size;\n        widget_resize(child, expanding_widgets_size, rem_height);\n        left += spacing;\n        rem -= expanding_widgets_size;\n        index++;\n      } else {\n        widget_move(child, left, widget_padding_get_top(WIDGET(b)));\n        left += widget_get_width(child);\n        left += spacing;\n      }\n    }\n  }\n  b->max_size += widget_padding_get_padding_width(WIDGET(b));\n}\n\nstatic void box_draw(widget *wid, cairo_t *draw) {\n  box *b = (box *)wid;\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    widget_draw(child, draw);\n  }\n}\n\nstatic void box_free(widget *wid) {\n  box *b = (box *)wid;\n\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    widget_free(child);\n  }\n  g_list_free(b->children);\n  g_free(b);\n}\n\nvoid box_add(box *wid, widget *child, gboolean expand) {\n  if (wid == NULL) {\n    return;\n  }\n  // Make sure box is width/heigh enough.\n  if (wid->type == ROFI_ORIENTATION_VERTICAL) {\n    int width = wid->widget.w;\n    width =\n        MAX(width, child->w + widget_padding_get_padding_width(WIDGET(wid)));\n    wid->widget.w = width;\n  } else {\n    int height = wid->widget.h;\n    height =\n        MAX(height, child->h + widget_padding_get_padding_height(WIDGET(wid)));\n    wid->widget.h = height;\n  }\n  child->expand = rofi_theme_get_boolean(child, \"expand\", expand);\n  g_assert(child->parent == WIDGET(wid));\n  wid->children = g_list_append(wid->children, (void *)child);\n  widget_update(WIDGET(wid));\n}\n\nstatic void box_resize(widget *wid, short w, short h) {\n  box *b = (box *)wid;\n  if (b->widget.w != w || b->widget.h != h) {\n    b->widget.w = w;\n    b->widget.h = h;\n    widget_update(wid);\n  }\n}\n\nstatic widget *box_find_mouse_target(widget *wid, WidgetType type, gint x,\n                                     gint y) {\n  box *b = (box *)wid;\n  for (GList *iter = g_list_first(b->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    if (!child->enabled) {\n      continue;\n    }\n    if (widget_intersect(child, x, y)) {\n      gint rx = x - child->x;\n      gint ry = y - child->y;\n      widget *target = widget_find_mouse_target(child, type, rx, ry);\n      if (target != NULL) {\n        return target;\n      }\n    }\n  }\n  return NULL;\n}\n\nstatic void box_set_state(widget *wid, const char *state) {\n  for (GList *iter = g_list_first(((box *)wid)->children); iter != NULL;\n       iter = g_list_next(iter)) {\n    widget *child = (widget *)iter->data;\n    widget_set_state(child, state);\n  }\n}\n\nbox *box_create(widget *parent, const char *name, RofiOrientation type) {\n  box *b = g_malloc0(sizeof(box));\n  // Initialize widget.\n  widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);\n  b->type = type;\n  b->widget.draw = box_draw;\n  b->widget.free = box_free;\n  b->widget.resize = box_resize;\n  b->widget.update = box_update;\n  b->widget.find_mouse_target = box_find_mouse_target;\n  b->widget.get_desired_height = box_get_desired_height;\n  b->widget.get_desired_width = box_get_desired_width;\n  b->widget.set_state = box_set_state;\n\n  b->type = rofi_theme_get_orientation(WIDGET(b), \"orientation\", b->type);\n\n  b->spacing = rofi_theme_get_distance(WIDGET(b), \"spacing\", DEFAULT_SPACING);\n  return b;\n}\n\nstatic void box_update(widget *wid) {\n  box *b = (box *)wid;\n  switch (b->type) {\n  case ROFI_ORIENTATION_VERTICAL:\n    vert_calculate_size(b);\n    break;\n  case ROFI_ORIENTATION_HORIZONTAL:\n  default:\n    hori_calculate_size(b);\n  }\n  if (wid->parent) {\n    widget_update(wid->parent);\n  }\n}\n"
  },
  {
    "path": "source/widgets/container.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this widget. */\n#define G_LOG_DOMAIN \"Widgets.Container\"\n#include \"config.h\"\n\n#include \"theme.h\"\n#include \"widgets/container.h\"\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <stdio.h>\n\nstruct _container {\n  widget widget;\n  widget *child;\n};\n\nstatic void container_update(widget *wid);\n\nstatic int container_get_desired_height(widget *wid, const int width) {\n  container *b = (container *)wid;\n  int height = 0;\n  if (b->child) {\n    height += widget_get_desired_height(b->child, width);\n  }\n  height += widget_padding_get_padding_height(wid);\n  return height;\n}\n\nstatic void container_draw(widget *wid, cairo_t *draw) {\n  container *b = (container *)wid;\n\n  widget_draw(b->child, draw);\n}\n\nstatic void container_free(widget *wid) {\n  container *b = (container *)wid;\n\n  widget_free(b->child);\n  g_free(b);\n}\n\nvoid container_add(container *cont, widget *child) {\n  if (cont == NULL) {\n    return;\n  }\n  cont->child = child;\n  g_assert(child->parent == WIDGET(cont));\n  widget_update(WIDGET(cont));\n}\n\nstatic void container_resize(widget *wid, short w, short h) {\n  container *b = (container *)wid;\n  if (b->widget.w != w || b->widget.h != h) {\n    b->widget.w = w;\n    b->widget.h = h;\n    widget_update(wid);\n  }\n}\n\nstatic widget *container_find_mouse_target(widget *wid, WidgetType type, gint x,\n                                           gint y) {\n  container *b = (container *)wid;\n  if (!widget_intersect(b->child, x, y)) {\n    return NULL;\n  }\n\n  x -= b->child->x;\n  y -= b->child->y;\n  return widget_find_mouse_target(b->child, type, x, y);\n}\n\nstatic void container_set_state(widget *wid, const char *state) {\n  container *b = (container *)wid;\n  widget_set_state(b->child, state);\n}\n\ncontainer *container_create(widget *parent, const char *name) {\n  container *b = g_malloc0(sizeof(container));\n  // Initialize widget.\n  widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);\n  b->widget.draw = container_draw;\n  b->widget.free = container_free;\n  b->widget.resize = container_resize;\n  b->widget.update = container_update;\n  b->widget.find_mouse_target = container_find_mouse_target;\n  b->widget.get_desired_height = container_get_desired_height;\n  b->widget.set_state = container_set_state;\n  return b;\n}\n\nstatic void container_update(widget *wid) {\n  container *b = (container *)wid;\n  if (b->child && b->child->enabled) {\n    widget_resize(WIDGET(b->child),\n                  widget_padding_get_remaining_width(WIDGET(b)),\n                  widget_padding_get_remaining_height(WIDGET(b)));\n    widget_move(WIDGET(b->child), widget_padding_get_left(WIDGET(b)),\n                widget_padding_get_top(WIDGET(b)));\n  }\n}\n"
  },
  {
    "path": "source/widgets/icon.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2018 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The log domain of this widget. */\n#include \"cairo.h\"\n#define G_LOG_DOMAIN \"Widgets.Icon\"\n#include \"config.h\"\n\n#include \"theme.h\"\n#include \"widgets/icon.h\"\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <stdio.h>\n\n#include \"rofi-icon-fetcher.h\"\n\nstruct _icon {\n  widget widget;\n\n  // Size of the icon.\n  int size;\n\n  int squared;\n\n  uint32_t icon_fetch_id;\n\n  double yalign, xalign;\n\n  // Source surface.\n  cairo_surface_t *icon;\n};\n\nstatic int icon_get_desired_height(widget *wid, G_GNUC_UNUSED const int width) {\n  icon *b = (icon *)wid;\n  int height = b->size;\n  if (b->squared == FALSE) {\n    if (b->icon) {\n      int iconh = cairo_image_surface_get_height(b->icon);\n      int iconw = cairo_image_surface_get_width(b->icon);\n      int icons = MAX(iconh, iconw);\n      double scale = (double)b->size / icons;\n      height = iconh * scale;\n    }\n  }\n  height += widget_padding_get_padding_height(wid);\n  return height;\n}\nstatic int icon_get_desired_width(widget *wid, G_GNUC_UNUSED const int height) {\n  icon *b = (icon *)wid;\n  int width = b->size;\n  if (b->squared == FALSE) {\n    if (b->icon) {\n      int iconh = cairo_image_surface_get_height(b->icon);\n      int iconw = cairo_image_surface_get_width(b->icon);\n      int icons = MAX(iconh, iconw);\n      double scale = (double)b->size / icons;\n      width = iconw * scale;\n    }\n  }\n  width += widget_padding_get_padding_width(wid);\n  return width;\n}\n\nstatic void icon_draw(widget *wid, cairo_t *draw) {\n  icon *b = (icon *)wid;\n  // If no icon is loaded. quit.\n  if (b->icon == NULL && b->icon_fetch_id > 0) {\n    b->icon = rofi_icon_fetcher_get(b->icon_fetch_id);\n    if (b->icon) {\n      cairo_surface_reference(b->icon);\n    }\n  }\n  if (b->icon == NULL) {\n    return;\n  }\n  int iconh = cairo_image_surface_get_height(b->icon);\n  int iconw = cairo_image_surface_get_width(b->icon);\n  int icons = MAX(iconh, iconw);\n  double scale = (double)b->size / icons;\n\n  int lpad = widget_padding_get_left(WIDGET(b));\n  int rpad = widget_padding_get_right(WIDGET(b));\n  int tpad = widget_padding_get_top(WIDGET(b));\n  int bpad = widget_padding_get_bottom(WIDGET(b));\n\n  cairo_save(draw);\n\n  cairo_translate(\n      draw, lpad + (b->widget.w - iconw * scale - lpad - rpad) * b->xalign,\n      tpad + (b->widget.h - iconh * scale - tpad - bpad) * b->yalign);\n  cairo_scale(draw, scale, scale);\n  if (rofi_theme_has_property(WIDGET(wid), P_COLOR, \"tint\")) {\n    cairo_pattern_t *pat = cairo_pattern_create_for_surface(b->icon);\n    cairo_set_source_rgb(draw, 0, 0, 0);\n    rofi_theme_get_color(WIDGET(wid), \"tint\", draw);\n    cairo_mask(draw, pat);\n    cairo_set_operator(draw, CAIRO_OPERATOR_HSL_LUMINOSITY);\n    cairo_pattern_destroy(pat);\n  }\n  cairo_set_source_surface(draw, b->icon, 0, 0);\n  cairo_paint(draw);\n  cairo_restore(draw);\n}\n\nstatic void icon_free(widget *wid) {\n  icon *b = (icon *)wid;\n\n  if (b->icon) {\n    cairo_surface_destroy(b->icon);\n  }\n\n  g_free(b);\n}\n\nstatic void icon_resize(widget *wid, short w, short h) {\n  icon *b = (icon *)wid;\n  if (b->widget.w != w || b->widget.h != h) {\n    b->widget.w = w;\n    b->widget.h = h;\n    widget_update(wid);\n  }\n}\n\nvoid icon_set_surface(icon *icon_widget, cairo_surface_t *surf) {\n  icon_widget->icon_fetch_id = 0;\n  if (icon_widget->icon) {\n    cairo_surface_destroy(icon_widget->icon);\n    icon_widget->icon = NULL;\n  }\n  if (surf) {\n    cairo_surface_reference(surf);\n    icon_widget->icon = surf;\n  }\n  widget_queue_redraw(WIDGET(icon_widget));\n}\n\nicon *icon_create(widget *parent, const char *name) {\n  icon *b = g_malloc0(sizeof(icon));\n\n  b->size = 16;\n  // Initialize widget.\n  widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);\n  b->widget.draw = icon_draw;\n  b->widget.free = icon_free;\n  b->widget.resize = icon_resize;\n  b->widget.get_desired_height = icon_get_desired_height;\n  b->widget.get_desired_width = icon_get_desired_width;\n\n  RofiDistance d = rofi_theme_get_distance(WIDGET(b), \"size\", b->size);\n  b->size = distance_get_pixel(d, ROFI_ORIENTATION_VERTICAL);\n\n  b->squared = rofi_theme_get_boolean(WIDGET(b), \"squared\", TRUE);\n\n  const char *filename = rofi_theme_get_string(WIDGET(b), \"filename\", NULL);\n  if (filename) {\n    b->icon_fetch_id = rofi_icon_fetcher_query(filename, b->size);\n  }\n  b->yalign = rofi_theme_get_double(WIDGET(b), \"vertical-align\", 0.5);\n  b->yalign = MAX(0, MIN(1.0, b->yalign));\n  b->xalign = rofi_theme_get_double(WIDGET(b), \"horizontal-align\", 0.5);\n  b->xalign = MAX(0, MIN(1.0, b->xalign));\n\n  return b;\n}\n"
  },
  {
    "path": "source/widgets/listview.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"config.h\"\n#include <glib.h>\n#include <widgets/box.h>\n#include <widgets/icon.h>\n#include <widgets/listview.h>\n#include <widgets/scrollbar.h>\n#include <widgets/textbox.h>\n#include <widgets/widget.h>\n\n#include \"helper.h\"\n#include \"settings.h\"\n#include \"theme.h\"\n#include \"view.h\"\n\n#include \"timings.h\"\n\n/** Default spacing between the elements in the listview. */\n#define DEFAULT_SPACING 2\n\n/**\n * Orientation of the listview\n */\n/** Vertical (classical) list */\n#define LISTVIEW ROFI_ORIENTATION_VERTICAL\n/** Horizontal list. (barview) */\n#define BARVIEW ROFI_ORIENTATION_HORIZONTAL\n\n/**\n * The moving direction of the selection, this (in barview) affects the\n * scrolling.\n */\ntypedef enum { LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 1 } MoveDirection;\n\ntypedef struct {\n  box *box;\n  textbox *textbox;\n  textbox *index;\n  icon *icon;\n} _listview_row;\n\nstruct _listview {\n  widget widget;\n\n  RofiOrientation type;\n\n  // RChanged\n  // Text needs to be repainted.\n  unsigned int rchanged;\n\n  // The direction we pack the widgets.\n  RofiOrientation pack_direction;\n  // Administration\n\n  unsigned int cur_page;\n  unsigned int last_offset;\n  unsigned int selected;\n\n  unsigned int element_height;\n  unsigned int max_rows;\n  unsigned int max_elements;\n\n  //\n  gboolean fixed_columns;\n  unsigned int cur_columns;\n  unsigned int req_elements;\n  unsigned int cur_elements;\n\n  RofiDistance spacing;\n  unsigned int menu_lines;\n  unsigned int max_displayed_lines;\n  unsigned int menu_columns;\n  unsigned int fixed_num_lines;\n  unsigned int dynamic;\n  unsigned int eh;\n  unsigned int reverse;\n  gboolean require_input;\n  gboolean filtered;\n\n  gboolean cycle;\n\n  ScrollType scroll_type;\n\n  _listview_row *boxes;\n  scrollbar *scrollbar;\n\n  listview_update_callback callback;\n  void *udata;\n\n  listview_selection_changed_callback sc_callback;\n  void *sc_udata;\n\n  gboolean scrollbar_scroll;\n\n  guint32 last_click;\n  listview_mouse_activated_cb mouse_activated;\n  void *mouse_activated_data;\n\n  listview_page_changed_cb page_callback;\n\n  char *listview_name;\n\n  PangoEllipsizeMode emode;\n  /** Barview */\n  struct {\n    MoveDirection direction;\n    unsigned int cur_visible;\n  } barview;\n};\n/**\n * Names used for theming the elements in the listview.\n * Each row can have 3 modes,  normal, selected and alternate.\n * Each row can have 3 states, normal, urgent and active.\n */\nconst char *const listview_theme_prop_names[][3] = {\n    /** Normal row */\n    {\"normal.normal\", \"selected.normal\", \"alternate.normal\"},\n    /** Urgent row */\n    {\"normal.urgent\", \"selected.urgent\", \"alternate.urgent\"},\n    /** Active row */\n    {\"normal.active\", \"selected.active\", \"alternate.active\"},\n};\n\nstatic void listview_set_state(_listview_row r, TextBoxFontType tbft) {\n  widget *w = WIDGET(r.box);\n  TextBoxFontType t = tbft & STATE_MASK;\n  if (w == NULL) {\n    return;\n  }\n  // ACTIVE has priority over URGENT if both set.\n  if (t == (URGENT | ACTIVE)) {\n    t = ACTIVE;\n  }\n  switch ((tbft & FMOD_MASK)) {\n  case HIGHLIGHT:\n    widget_set_state(w, listview_theme_prop_names[t][1]);\n    break;\n  case ALT:\n    widget_set_state(w, listview_theme_prop_names[t][2]);\n    break;\n  default:\n    widget_set_state(w, listview_theme_prop_names[t][0]);\n    break;\n  }\n}\nstatic void listview_add_widget(listview *lv, _listview_row *row, widget *wid,\n                                const char *label) {\n  if (strcasecmp(label, \"element-icon\") == 0) {\n    row->icon = icon_create(WIDGET(wid), \"element-icon\");\n    box_add((box *)wid, WIDGET(row->icon), FALSE);\n  } else if (strcasecmp(label, \"element-text\") == 0) {\n    row->textbox =\n        textbox_create(WIDGET(wid), WIDGET_TYPE_TEXTBOX_TEXT, \"element-text\",\n                       TB_AUTOHEIGHT, NORMAL, \"DDD\", 0, 0);\n    textbox_set_ellipsize(row->textbox, lv->emode);\n    box_add((box *)wid, WIDGET(row->textbox), TRUE);\n  } else if (strcasecmp(label, \"element-index\") == 0) {\n    row->index =\n        textbox_create(WIDGET(wid), WIDGET_TYPE_TEXTBOX_TEXT, \"element-index\",\n                       TB_AUTOHEIGHT, NORMAL, \" \", 0, 0);\n    box_add((box *)wid, WIDGET(row->index), FALSE);\n  } else if (strncasecmp(label, \"textbox\", 7) == 0) {\n    textbox *textbox_custom =\n        textbox_create(wid, WIDGET_TYPE_TEXTBOX_TEXT, label,\n                       TB_AUTOHEIGHT | TB_WRAP, NORMAL, \"\", 0, 0);\n    box_add((box *)wid, WIDGET(textbox_custom), TRUE);\n  } else if (strncasecmp(label, \"button\", 6) == 0) {\n    textbox *button_custom =\n        textbox_create(wid, WIDGET_TYPE_EDITBOX, label, TB_AUTOHEIGHT | TB_WRAP,\n                       NORMAL, \"\", 0, 0);\n    box_add((box *)wid, WIDGET(button_custom), TRUE);\n    widget_set_trigger_action_handler(WIDGET(button_custom),\n                                      textbox_button_trigger_action, lv->udata);\n  } else if (strncasecmp(label, \"icon\", 4) == 0) {\n    icon *icon_custom = icon_create(wid, label);\n    /* small hack to make it clickable */\n    const char *type =\n        rofi_theme_get_string(WIDGET(icon_custom), \"action\", NULL);\n    if (type) {\n      WIDGET(icon_custom)->type = WIDGET_TYPE_EDITBOX;\n    }\n    box_add((box *)wid, WIDGET(icon_custom), TRUE);\n    widget_set_trigger_action_handler(WIDGET(icon_custom),\n                                      textbox_button_trigger_action, lv->udata);\n  } else {\n    widget *wid2 = (widget *)box_create(wid, label, ROFI_ORIENTATION_VERTICAL);\n    box_add((box *)wid, WIDGET(wid2), TRUE);\n    GList *list = rofi_theme_get_list_strings(\n        WIDGET(wid2),\n        \"children\"); // rofi_theme_get_list(WIDGET(wid2), \"children\", \"\");\n    for (GList *iter = g_list_first(list); iter != NULL;\n         iter = g_list_next(iter)) {\n      listview_add_widget(lv, row, wid2, (const char *)iter->data);\n    }\n  }\n}\n\nstatic void listview_create_row(listview *lv, _listview_row *row) {\n  row->box = box_create(WIDGET(lv), \"element\", ROFI_ORIENTATION_HORIZONTAL);\n  widget_set_type(WIDGET(row->box), WIDGET_TYPE_LISTVIEW_ELEMENT);\n  GList *list = NULL;\n  list = rofi_theme_get_list_strings(WIDGET(row->box), \"children\");\n  if (list == NULL) {\n    if (config.show_icons) {\n      list = g_list_append(list, g_strdup(\"element-icon\"));\n      list = g_list_append(list, g_strdup(\"element-text\"));\n    } else {\n      list = g_list_append(list, g_strdup(\"element-text\"));\n    }\n  }\n\n  row->textbox = NULL;\n  row->icon = NULL;\n  row->index = NULL;\n\n  for (GList *iter = g_list_first(list); iter != NULL;\n       iter = g_list_next(iter)) {\n    listview_add_widget(lv, row, WIDGET(row->box), (const char *)iter->data);\n  }\n  g_list_free_full(list, g_free);\n}\n\nstatic int listview_get_desired_height(widget *wid, const int width);\n\nstatic void listview_free(widget *wid) {\n  listview *lv = (listview *)wid;\n  for (unsigned int i = 0; i < lv->cur_elements; i++) {\n    widget_free(WIDGET(lv->boxes[i].box));\n  }\n  g_free(lv->boxes);\n\n  g_free(lv->listview_name);\n  widget_free(WIDGET(lv->scrollbar));\n  g_free(lv);\n}\nstatic unsigned int scroll_per_page_barview(listview *lv) {\n  unsigned int offset = lv->last_offset;\n\n  // selected row is always visible.\n  // If selected is visible do not scroll.\n  if (lv->selected < lv->last_offset) {\n    offset = lv->selected;\n    lv->rchanged = TRUE;\n  } else if (lv->selected >= (lv->last_offset + lv->barview.cur_visible)) {\n    offset = lv->selected;\n    lv->rchanged = TRUE;\n  }\n  return offset;\n}\nstatic unsigned int scroll_per_page(listview *lv) {\n  int offset = 0;\n\n  // selected row is always visible.\n  // If selected is visible do not scroll.\n  if (((lv->selected - (lv->last_offset)) < (lv->max_elements)) &&\n      (lv->selected >= (lv->last_offset))) {\n    offset = lv->last_offset;\n  } else {\n    // Do paginating\n    unsigned int page =\n        (lv->max_elements > 0) ? (lv->selected / lv->max_elements) : 0;\n    offset = page * lv->max_elements;\n    if (page != lv->cur_page) {\n\n      if (lv->page_callback)\n        lv->page_callback();\n\n      lv->cur_page = page;\n      lv->rchanged = TRUE;\n    }\n    // Set the position\n    // scrollbar_set_handle ( lv->scrollbar, page * lv->max_elements );\n  }\n  return offset;\n}\n\n// For vertical packing flow\nstatic unsigned int scroll_continious_elements(listview *lv) {\n  unsigned int vmid = (lv->max_rows - 1) / 2;\n  unsigned int hmid = (lv->menu_columns - 1) / 2;\n  unsigned int middle = (lv->max_rows * hmid) + vmid;\n  unsigned int offset = 0;\n  if (lv->selected > middle) {\n    if (lv->selected < (lv->req_elements - (lv->max_elements - middle))) {\n      offset = lv->selected - middle;\n    }\n    // Don't go below zero.\n    else if (lv->req_elements > lv->max_elements) {\n      offset = lv->req_elements - lv->max_elements;\n    }\n  }\n  if (offset != lv->cur_page) {\n    // scrollbar_set_handle ( lv->scrollbar, offset );\n    lv->cur_page = offset;\n    lv->rchanged = TRUE;\n  }\n  return offset;\n}\n\n// For horizontal packing flow\nstatic unsigned int scroll_continious_rows(listview *lv) {\n  unsigned int middle, selected, req_rows, offset;\n  middle = (lv->max_rows - 1) / 2;\n  selected = lv->selected / lv->menu_columns;\n  req_rows = (lv->req_elements + lv->menu_columns - 1) / lv->menu_columns;\n  offset = 0;\n  if (selected > middle) {\n    if (selected < (req_rows - (lv->max_rows - middle))) {\n      offset = selected - middle;\n    }\n    // Don't go below zero.\n    else if (req_rows > lv->max_rows) {\n      offset = req_rows - lv->max_rows;\n    }\n  }\n  offset *= lv->menu_columns;\n  if (offset != lv->cur_page) {\n    // scrollbar_set_handle ( lv->scrollbar, offset );\n    lv->cur_page = offset;\n    lv->rchanged = TRUE;\n  }\n  return offset;\n}\n\nstatic void update_element(listview *lv, unsigned int tb, unsigned int index,\n                           gboolean full) {\n  // Select drawing mode\n  TextBoxFontType type = (index & 1) == 0 ? NORMAL : ALT;\n  type = (index) == lv->selected ? HIGHLIGHT : type;\n\n  if (lv->boxes[tb].index) {\n    if (index < 10) {\n      char str[2] = {((index + 1) % 10) + '0', '\\0'};\n      textbox_text(lv->boxes[tb].index, str);\n    } else {\n      textbox_text(lv->boxes[tb].index, \" \");\n    }\n  }\n  if (lv->callback) {\n    lv->callback(lv->boxes[tb].textbox, lv->boxes[tb].icon, index, lv->udata,\n                 &type, full);\n    listview_set_state(lv->boxes[tb], type);\n  }\n}\n\nstatic void barview_draw(widget *wid, cairo_t *draw) {\n  unsigned int offset = 0;\n  listview *lv = (listview *)wid;\n  offset = scroll_per_page_barview(lv);\n  lv->last_offset = offset;\n  int spacing_hori =\n      distance_get_pixel(lv->spacing, ROFI_ORIENTATION_HORIZONTAL);\n\n  int left_offset = widget_padding_get_left(wid);\n  int right_offset = lv->widget.w - widget_padding_get_right(wid);\n  int top_offset = widget_padding_get_top(wid);\n  if (lv->cur_elements > 0) {\n    // Set new x/y position.\n    unsigned int max = MIN(lv->cur_elements, lv->req_elements - offset);\n    if (lv->rchanged) {\n      int first = TRUE;\n      int width = lv->widget.w;\n      lv->barview.cur_visible = 0;\n      width -= widget_padding_get_padding_width(wid);\n      if (lv->barview.direction == LEFT_TO_RIGHT) {\n        for (unsigned int i = 0; i < max && width > 0; i++) {\n          update_element(lv, i, i + offset, TRUE);\n          int twidth = widget_get_desired_width(WIDGET(lv->boxes[i].box),\n                                                lv->element_height);\n          if (twidth >= width) {\n            if (!first) {\n              break;\n            }\n            twidth = width;\n          }\n          widget_move(WIDGET(lv->boxes[i].box), left_offset, top_offset);\n          widget_resize(WIDGET(lv->boxes[i].box), twidth, lv->element_height);\n\n          widget_draw(WIDGET(lv->boxes[i].box), draw);\n          width -= twidth + spacing_hori;\n          left_offset += twidth + spacing_hori;\n          first = FALSE;\n          lv->barview.cur_visible++;\n        }\n      } else {\n        for (unsigned int i = 0;\n             i < lv->cur_elements && width > 0 && i <= offset; i++) {\n          update_element(lv, i, offset - i, TRUE);\n          int twidth = widget_get_desired_width(WIDGET(lv->boxes[i].box),\n                                                lv->element_height);\n          if (twidth >= width) {\n            if (!first) {\n              break;\n            }\n            twidth = width;\n          }\n          right_offset -= twidth;\n          widget_move(WIDGET(lv->boxes[i].box), right_offset, top_offset);\n          widget_resize(WIDGET(lv->boxes[i].box), twidth, lv->element_height);\n\n          widget_draw(WIDGET(lv->boxes[i].box), draw);\n          width -= twidth + spacing_hori;\n          right_offset -= spacing_hori;\n          first = FALSE;\n          lv->barview.cur_visible++;\n        }\n        offset -= lv->barview.cur_visible - 1;\n        lv->last_offset = offset;\n        for (unsigned int i = 0; i < (lv->barview.cur_visible / 2); i++) {\n          _listview_row temp = lv->boxes[i];\n          int sw = lv->barview.cur_visible - i - 1;\n          lv->boxes[i] = lv->boxes[sw];\n          lv->boxes[sw] = temp;\n        }\n      }\n      lv->rchanged = FALSE;\n    } else {\n      for (unsigned int i = 0; i < lv->barview.cur_visible; i++) {\n        update_element(lv, i, i + offset, TRUE);\n        widget_draw(WIDGET(lv->boxes[i].box), draw);\n      }\n    }\n  }\n}\n\nstatic void listview_draw(widget *wid, cairo_t *draw) {\n  unsigned int offset = 0;\n  listview *lv = (listview *)wid;\n  if (lv->scroll_type == LISTVIEW_SCROLL_PER_PAGE) {\n    offset = scroll_per_page(lv);\n  } else if (lv->pack_direction == ROFI_ORIENTATION_VERTICAL) {\n    offset = scroll_continious_elements(lv);\n  } else {\n    offset = scroll_continious_rows(lv);\n  }\n  // Set these all together to make sure they update consistently.\n  scrollbar_set_max_value(lv->scrollbar, lv->req_elements);\n  scrollbar_set_handle_length(lv->scrollbar, lv->cur_columns * lv->max_rows);\n  if (lv->reverse) {\n    scrollbar_set_handle(lv->scrollbar, lv->req_elements - lv->selected - 1);\n  } else {\n    scrollbar_set_handle(lv->scrollbar, lv->selected);\n  }\n  lv->last_offset = offset;\n  int spacing_vert = distance_get_pixel(lv->spacing, ROFI_ORIENTATION_VERTICAL);\n  int spacing_hori =\n      distance_get_pixel(lv->spacing, ROFI_ORIENTATION_HORIZONTAL);\n\n  int left_offset = widget_padding_get_left(wid);\n  int top_offset = widget_padding_get_top(wid);\n  /*\n     if ( lv->scrollbar->widget.index == 0 ) {\n      left_offset += spacing_hori + lv->scrollbar->widget.w;\n     }\n   */\n  if (lv->cur_elements > 0 && lv->max_rows > 0) {\n    // Set new x/y position.\n    unsigned int max = MIN(lv->cur_elements, lv->req_elements - offset);\n    if (lv->rchanged) {\n      unsigned int width = lv->widget.w;\n      width -= widget_padding_get_padding_width(wid);\n      if (widget_enabled(WIDGET(lv->scrollbar))) {\n        width -= spacing_hori;\n        width -= widget_get_width(WIDGET(lv->scrollbar));\n      }\n      unsigned int element_width =\n          (width - spacing_hori * (lv->cur_columns - 1)) / lv->cur_columns;\n\n      int d = width - (element_width + spacing_hori) * (lv->cur_columns - 1) -\n              element_width;\n      if (lv->cur_columns > 1) {\n        int diff = d / (lv->cur_columns - 1);\n        if (diff >= 1) {\n          spacing_hori += 1;\n          d -= lv->cur_columns - 1;\n        }\n      }\n      for (unsigned int i = 0; i < max; i++) {\n        if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) {\n          unsigned int ex = left_offset + ((i) % lv->cur_columns) *\n                                              (element_width + spacing_hori);\n          unsigned int ey = 0;\n          if (lv->reverse) {\n            ey = wid->h -\n                 (widget_padding_get_bottom(wid) +\n                  ((i) / lv->cur_columns) *\n                      (lv->element_height + spacing_vert)) -\n                 lv->element_height;\n\n            if ((i) / lv->cur_columns == (lv->cur_columns - 1)) {\n              ex += d;\n            }\n          } else {\n            ey = top_offset +\n                 ((i) / lv->cur_columns) * (lv->element_height + spacing_vert);\n\n            if ((i) / lv->cur_columns == (lv->cur_columns - 1)) {\n              ex += d;\n            }\n          }\n          widget_move(WIDGET(lv->boxes[i].box), ex, ey);\n          widget_resize(WIDGET(lv->boxes[i].box), element_width,\n                        lv->element_height);\n\n        } else {\n          unsigned int ex = left_offset + ((i) / lv->max_rows) *\n                                              (element_width + spacing_hori);\n\n          if ((i) / lv->max_rows == (lv->cur_columns - 1)) {\n            ex += d;\n          }\n          unsigned int ey = 0;\n          if (lv->reverse) {\n            ey = wid->h -\n                 (widget_padding_get_bottom(wid) +\n                  ((i) % lv->max_rows) * (lv->element_height + spacing_vert)) -\n                 lv->element_height;\n          } else {\n            ey = top_offset +\n                 ((i) % lv->max_rows) * (lv->element_height + spacing_vert);\n          }\n          widget_move(WIDGET(lv->boxes[i].box), ex, ey);\n          widget_resize(WIDGET(lv->boxes[i].box), element_width,\n                        lv->element_height);\n        }\n        update_element(lv, i, i + offset, TRUE);\n        widget_draw(WIDGET(lv->boxes[i].box), draw);\n      }\n      lv->rchanged = FALSE;\n    } else {\n      for (unsigned int i = 0; i < max; i++) {\n        update_element(lv, i, i + offset, TRUE);\n        widget_draw(WIDGET(lv->boxes[i].box), draw);\n      }\n    }\n  }\n  widget_draw(WIDGET(lv->scrollbar), draw);\n}\nstatic WidgetTriggerActionResult\nlistview_element_trigger_action(widget *wid,\n                                MouseBindingListviewElementAction action,\n                                gint x, gint y, void *user_data);\nstatic gboolean listview_element_motion_notify(widget *wid, gint x, gint y);\n\nstatic void _listview_draw(widget *wid, cairo_t *draw) {\n  listview *lv = (listview *)wid;\n  if (lv->type == LISTVIEW) {\n    listview_draw(wid, draw);\n  } else {\n    barview_draw(wid, draw);\n  }\n}\n/**\n * State names used for theming.\n */\nstatic void listview_recompute_elements(listview *lv) {\n  unsigned int newne = 0;\n  if (lv->max_rows == 0) {\n    return;\n  }\n  if (!(lv->fixed_columns) && lv->req_elements < lv->max_elements) {\n    newne = lv->req_elements;\n    if (lv->pack_direction == ROFI_ORIENTATION_VERTICAL) {\n      lv->cur_columns = (lv->req_elements + (lv->max_rows - 1)) / lv->max_rows;\n    } else {\n      lv->cur_columns = lv->menu_columns;\n      if (lv->req_elements < lv->menu_columns) {\n        lv->cur_columns = lv->req_elements;\n      }\n    }\n  } else {\n    newne = MIN(lv->req_elements, lv->max_elements);\n    lv->cur_columns = lv->menu_columns;\n  }\n  for (unsigned int i = newne; i < lv->cur_elements; i++) {\n    widget_free(WIDGET(lv->boxes[i].box));\n  }\n  lv->boxes = g_realloc(lv->boxes, newne * sizeof(_listview_row));\n  if (newne > 0) {\n    for (unsigned int i = lv->cur_elements; i < newne; i++) {\n      listview_create_row(lv, &(lv->boxes[i]));\n      widget *wid = WIDGET(lv->boxes[i].box);\n      widget_set_trigger_action_handler(wid, listview_element_trigger_action,\n                                        lv);\n      if (wid != NULL) {\n        wid->motion_notify = listview_element_motion_notify;\n      }\n\n      listview_set_state(lv->boxes[i], NORMAL);\n    }\n  }\n  lv->rchanged = TRUE;\n  lv->cur_elements = newne;\n}\n\nvoid listview_set_num_elements(listview *lv, unsigned int rows) {\n  if (lv == NULL) {\n    return;\n  }\n  TICK_N(\"listview_set_num_elements\");\n  lv->req_elements = rows;\n  if (lv->require_input && !lv->filtered) {\n    lv->req_elements = 0;\n  }\n  listview_set_selected(lv, lv->selected);\n  TICK_N(\"Set selected\");\n  listview_recompute_elements(lv);\n  TICK_N(\"recompute elements\");\n  widget_queue_redraw(WIDGET(lv));\n  TICK_N(\"queue redraw\");\n}\n\nunsigned int listview_get_selected(listview *lv) {\n  if (lv != NULL) {\n    return lv->selected;\n  }\n  return 0;\n}\n\nvoid listview_set_selected(listview *lv, unsigned int selected) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->req_elements > 0) {\n    lv->selected = MIN(selected, lv->req_elements - 1);\n    lv->barview.direction = LEFT_TO_RIGHT;\n    widget_queue_redraw(WIDGET(lv));\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n  } else {\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, UINT32_MAX, lv->sc_udata);\n    }\n  }\n}\n\nstatic void listview_resize(widget *wid, short w, short h) {\n  listview *lv = (listview *)wid;\n  lv->widget.w = MAX(0, w);\n  lv->widget.h = MAX(0, h);\n  int height = lv->widget.h - widget_padding_get_padding_height(WIDGET(lv));\n  int spacing_vert = distance_get_pixel(lv->spacing, ROFI_ORIENTATION_VERTICAL);\n  if (lv->widget.h == 0) {\n    lv->max_rows = lv->menu_lines;\n  } else {\n    lv->max_rows =\n        (spacing_vert + height) / (lv->element_height + spacing_vert);\n  }\n  lv->max_elements = lv->max_rows * lv->menu_columns;\n\n  widget_move(WIDGET(lv->scrollbar),\n              lv->widget.w - widget_padding_get_right(WIDGET(lv)) -\n                  widget_get_width(WIDGET(lv->scrollbar)),\n              widget_padding_get_top(WIDGET(lv)));\n\n  widget_resize(WIDGET(lv->scrollbar), widget_get_width(WIDGET(lv->scrollbar)),\n                height);\n\n  if (lv->type == BARVIEW) {\n    lv->max_elements = lv->menu_lines;\n  }\n\n  listview_recompute_elements(lv);\n  widget_queue_redraw(wid);\n}\n\nstatic widget *listview_find_mouse_target(widget *wid, WidgetType type, gint x,\n                                          gint y) {\n  widget *target = NULL;\n  gint rx, ry;\n  listview *lv = (listview *)wid;\n  if (widget_enabled(WIDGET(lv->scrollbar)) &&\n      widget_intersect(WIDGET(lv->scrollbar), x, y)) {\n    rx = x - widget_get_x_pos(WIDGET(lv->scrollbar));\n    ry = y - widget_get_y_pos(WIDGET(lv->scrollbar));\n    target = widget_find_mouse_target(WIDGET(lv->scrollbar), type, rx, ry);\n  }\n\n  unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);\n  unsigned int i;\n  for (i = 0; i < max && target == NULL; i++) {\n    widget *w = WIDGET(lv->boxes[i].box);\n    if (widget_intersect(w, x, y)) {\n      rx = x - widget_get_x_pos(w);\n      ry = y - widget_get_y_pos(w);\n      target = widget_find_mouse_target(w, type, rx, ry);\n    }\n  }\n\n  return target;\n}\n\nstatic WidgetTriggerActionResult\nlistview_trigger_action(widget *wid, MouseBindingListviewAction action,\n                        G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y,\n                        G_GNUC_UNUSED void *user_data) {\n  listview *lv = (listview *)wid;\n  switch (action) {\n  case SCROLL_LEFT:\n    listview_nav_left(lv);\n    break;\n  case SCROLL_RIGHT:\n    listview_nav_right(lv);\n    break;\n  case SCROLL_DOWN:\n    listview_nav_down(lv);\n    break;\n  case SCROLL_UP:\n    listview_nav_up(lv);\n    break;\n  }\n  return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n}\n\nstatic WidgetTriggerActionResult listview_element_trigger_action(\n    widget *wid, MouseBindingListviewElementAction action, G_GNUC_UNUSED gint x,\n    G_GNUC_UNUSED gint y, void *user_data) {\n  listview *lv = (listview *)user_data;\n  unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);\n  unsigned int i;\n  for (i = 0; i < max && WIDGET(lv->boxes[i].box) != wid; i++) {\n  }\n  if (i == max) {\n    return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;\n  }\n\n  gboolean custom = FALSE;\n  switch (action) {\n  case SELECT_HOVERED_ENTRY:\n    listview_set_selected(lv, lv->last_offset + i);\n    break;\n  case ACCEPT_HOVERED_CUSTOM:\n    custom = TRUE;\n    rofi_fallthrough;\n  case ACCEPT_HOVERED_ENTRY:\n    listview_set_selected(lv, lv->last_offset + i);\n    lv->mouse_activated(lv, custom, lv->mouse_activated_data);\n    break;\n  }\n  return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n}\n\nstatic gboolean listview_element_motion_notify(widget *wid,\n                                               G_GNUC_UNUSED gint x,\n                                               G_GNUC_UNUSED gint y) {\n  listview *lv = (listview *)wid->parent;\n  unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);\n  unsigned int i;\n  for (i = 0; i < max && WIDGET(lv->boxes[i].box) != wid; i++) {\n  }\n  if (i < max && (lv->last_offset + i) != listview_get_selected(lv)) {\n    listview_set_selected(lv, lv->last_offset + i);\n  }\n  return TRUE;\n}\n\nlistview *listview_create(widget *parent, const char *name,\n                          listview_update_callback cb,\n                          listview_page_changed_cb page_cb, void *udata,\n                          unsigned int eh, gboolean reverse) {\n  listview *lv = g_malloc0(sizeof(listview));\n  widget_init(WIDGET(lv), parent, WIDGET_TYPE_LISTVIEW, name);\n  lv->listview_name = g_strdup(name);\n  lv->widget.free = listview_free;\n  lv->widget.resize = listview_resize;\n  lv->widget.draw = _listview_draw;\n  lv->widget.find_mouse_target = listview_find_mouse_target;\n  lv->widget.trigger_action = listview_trigger_action;\n  lv->widget.get_desired_height = listview_get_desired_height;\n  lv->eh = eh;\n\n  lv->emode = PANGO_ELLIPSIZE_END;\n  lv->scrollbar = scrollbar_create(WIDGET(lv), \"scrollbar\");\n  // Calculate height of an element.\n  //\n  _listview_row row;\n  listview_create_row(lv, &row);\n  // FIXME: hack to scale hight correctly.\n  if (lv->eh > 1 && row.textbox) {\n    char buff[lv->eh * 2 + 1];\n    memset(buff, '\\0', lv->eh * 2 + 1);\n    for (unsigned int i = 0; i < (lv->eh - 1); i++) {\n      buff[i * 2] = 'a';\n      buff[i * 2 + 1] = '\\n';\n    };\n    textbox_moveresize(row.textbox, 0, 0, 100000000, -1);\n    textbox_text(row.textbox, buff);\n  }\n  // Make textbox very wide.\n  lv->element_height = widget_get_desired_height(WIDGET(row.box), 100000);\n  widget_free(WIDGET(row.box));\n\n  lv->callback = cb;\n  lv->udata = udata;\n\n  lv->page_callback = page_cb;\n\n  // Some settings.\n  lv->spacing = rofi_theme_get_distance(WIDGET(lv), \"spacing\", DEFAULT_SPACING);\n  lv->menu_columns =\n      rofi_theme_get_integer(WIDGET(lv), \"columns\", DEFAULT_MENU_COLUMNS);\n  lv->menu_lines =\n      rofi_theme_get_integer(WIDGET(lv), \"lines\", DEFAULT_MENU_LINES);\n  lv->fixed_num_lines = rofi_theme_get_boolean(WIDGET(lv), \"fixed-height\",\n                                               config.fixed_num_lines);\n  lv->dynamic = rofi_theme_get_boolean(WIDGET(lv), \"dynamic\", TRUE);\n  lv->reverse = rofi_theme_get_boolean(WIDGET(lv), \"reverse\", reverse);\n  lv->pack_direction =\n      rofi_theme_get_orientation(WIDGET(lv), \"flow\", ROFI_ORIENTATION_VERTICAL);\n  lv->cycle = rofi_theme_get_boolean(WIDGET(lv), \"cycle\", config.cycle);\n  lv->fixed_columns =\n      rofi_theme_get_boolean(WIDGET(lv), \"fixed-columns\", FALSE);\n\n  lv->require_input =\n      rofi_theme_get_boolean(WIDGET(lv), \"require-input\", FALSE);\n  lv->type = rofi_theme_get_orientation(WIDGET(lv), \"layout\",\n                                        ROFI_ORIENTATION_VERTICAL);\n  if (lv->type == LISTVIEW) {\n    listview_set_show_scrollbar(\n        lv, rofi_theme_get_boolean(WIDGET(lv), \"scrollbar\", FALSE));\n  } else {\n    listview_set_show_scrollbar(lv, FALSE);\n  }\n  return lv;\n}\n\n/**\n * Navigation commands.\n */\n\nstatic void listview_nav_up_int(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->req_elements == 0 || (lv->selected == 0 && !lv->cycle)) {\n    return;\n  }\n  if (lv->selected == 0) {\n    lv->selected = lv->req_elements;\n  }\n  lv->selected--;\n  lv->barview.direction = RIGHT_TO_LEFT;\n\n  if (lv->sc_callback) {\n    lv->sc_callback(lv, lv->selected, lv->sc_udata);\n  }\n  widget_queue_redraw(WIDGET(lv));\n}\nstatic void listview_nav_down_int(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->req_elements == 0 ||\n      (lv->selected == (lv->req_elements - 1) && !lv->cycle)) {\n    return;\n  }\n  lv->selected = lv->selected < lv->req_elements - 1\n                     ? MIN(lv->req_elements - 1, lv->selected + 1)\n                     : 0;\n  lv->barview.direction = LEFT_TO_RIGHT;\n  if (lv->sc_callback) {\n    lv->sc_callback(lv, lv->selected, lv->sc_udata);\n  }\n  widget_queue_redraw(WIDGET(lv));\n}\nvoid listview_nav_next(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  listview_nav_down_int(lv);\n}\nvoid listview_nav_prev(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  listview_nav_up_int(lv);\n}\n\nstatic void listview_nav_column_left_int(listview *lv) {\n  if (lv->selected >= lv->cur_columns) {\n    lv->selected -= lv->cur_columns;\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n    widget_queue_redraw(WIDGET(lv));\n  }\n}\nstatic void listview_nav_column_right_int(listview *lv) {\n  if ((lv->selected + lv->cur_columns) < lv->req_elements) {\n    lv->selected += lv->cur_columns;\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n    widget_queue_redraw(WIDGET(lv));\n  }\n}\n\nvoid listview_nav_up(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) {\n    if (lv->reverse) {\n      listview_nav_column_right_int(lv);\n    } else {\n      listview_nav_column_left_int(lv);\n    }\n    return;\n  }\n  if (lv->reverse) {\n    listview_nav_down_int(lv);\n  } else {\n    listview_nav_up_int(lv);\n  }\n}\nvoid listview_nav_down(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) {\n    if (lv->reverse) {\n      listview_nav_column_left_int(lv);\n    } else {\n      listview_nav_column_right_int(lv);\n    }\n    return;\n  }\n  if (lv->reverse) {\n    listview_nav_up_int(lv);\n  } else {\n    listview_nav_down_int(lv);\n  }\n}\n\nvoid listview_nav_left(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->max_rows == 0) {\n    return;\n  }\n  if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) {\n    listview_nav_up_int(lv);\n    return;\n  }\n  if (lv->type == BARVIEW) {\n    listview_nav_up_int(lv);\n    return;\n  }\n  if (lv->selected >= lv->max_rows) {\n    lv->selected -= lv->max_rows;\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n    widget_queue_redraw(WIDGET(lv));\n  }\n}\nvoid listview_nav_right(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->max_rows == 0) {\n    return;\n  }\n  if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) {\n    listview_nav_down_int(lv);\n    return;\n  }\n  if (lv->type == BARVIEW) {\n    listview_nav_down_int(lv);\n    return;\n  }\n  if ((lv->selected + lv->max_rows) < lv->req_elements) {\n    lv->selected += lv->max_rows;\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n    widget_queue_redraw(WIDGET(lv));\n  } else if (lv->selected < (lv->req_elements - 1)) {\n    // We do not want to move to last item, UNLESS the last column is only\n    // partially filled, then we still want to move column and select last\n    // entry. First check the column we are currently in.\n    int col = lv->selected / lv->max_rows;\n    // Check total number of columns.\n    int ncol = lv->req_elements / lv->max_rows;\n    // If there is an extra column, move.\n    if (col != ncol) {\n      lv->selected = lv->req_elements - 1;\n      if (lv->sc_callback) {\n        lv->sc_callback(lv, lv->selected, lv->sc_udata);\n      }\n      widget_queue_redraw(WIDGET(lv));\n    }\n  }\n}\n\nstatic void listview_nav_page_prev_int(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->type == BARVIEW) {\n    if (lv->last_offset == 0) {\n      lv->selected = 0;\n    } else {\n      lv->selected = lv->last_offset - 1;\n    }\n    lv->barview.direction = RIGHT_TO_LEFT;\n    widget_queue_redraw(WIDGET(lv));\n    return;\n  }\n\n  if (lv->selected < lv->max_elements) {\n    lv->selected = 0;\n  } else {\n    lv->selected -= (lv->max_elements);\n  }\n  if (lv->sc_callback) {\n    lv->sc_callback(lv, lv->selected, lv->sc_udata);\n  }\n  widget_queue_redraw(WIDGET(lv));\n}\nstatic void listview_nav_page_next_int(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->req_elements == 0) {\n    return;\n  }\n  if (lv->type == BARVIEW) {\n    unsigned int new = lv->last_offset + lv->barview.cur_visible;\n    lv->selected = MIN(new, lv->req_elements - 1);\n    lv->barview.direction = LEFT_TO_RIGHT;\n\n    if (lv->sc_callback) {\n      lv->sc_callback(lv, lv->selected, lv->sc_udata);\n    }\n    widget_queue_redraw(WIDGET(lv));\n    return;\n  }\n  lv->selected += (lv->max_elements);\n  if (lv->selected >= lv->req_elements) {\n    lv->selected = lv->req_elements - 1;\n  }\n  if (lv->sc_callback) {\n    lv->sc_callback(lv, lv->selected, lv->sc_udata);\n  }\n  widget_queue_redraw(WIDGET(lv));\n}\n\nvoid listview_nav_page_prev(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->reverse) {\n    listview_nav_page_next_int(lv);\n  } else {\n    listview_nav_page_prev_int(lv);\n  }\n}\nvoid listview_nav_page_next(listview *lv) {\n  if (lv == NULL) {\n    return;\n  }\n  if (lv->reverse) {\n    listview_nav_page_prev_int(lv);\n  } else {\n    listview_nav_page_next_int(lv);\n  }\n}\n\nstatic int listview_get_desired_height(widget *wid,\n                                       G_GNUC_UNUSED const int width) {\n  listview *lv = (listview *)wid;\n  if (lv == NULL || lv->widget.enabled == FALSE) {\n    return 0;\n  }\n  int spacing = distance_get_pixel(lv->spacing, ROFI_ORIENTATION_VERTICAL);\n  int h = lv->menu_lines;\n  if (!(lv->fixed_num_lines)) {\n    if (lv->dynamic) {\n      h = MIN(lv->menu_lines, lv->req_elements);\n    } else {\n      h = MIN(lv->menu_lines, lv->max_displayed_lines);\n    }\n  }\n  if (lv->type == BARVIEW) {\n    h = MIN(h, 1);\n  }\n  if (h == 0) {\n    if (lv->dynamic && !lv->fixed_num_lines) {\n      // Hide widget fully.\n      return 0;\n    }\n    return widget_padding_get_padding_height(WIDGET(lv));\n  }\n  int height = widget_padding_get_padding_height(WIDGET(lv));\n  height += h * (lv->element_height + spacing) - spacing;\n  return height;\n}\n\nvoid listview_set_show_scrollbar(listview *lv, gboolean enabled) {\n  if (lv) {\n    if (enabled) {\n      widget_enable(WIDGET(lv->scrollbar));\n    } else {\n      widget_disable(WIDGET(lv->scrollbar));\n    }\n    listview_recompute_elements(lv);\n  }\n}\n\nvoid listview_set_scroll_type(listview *lv, ScrollType type) {\n  if (lv) {\n    lv->scroll_type = type;\n  }\n}\n\nvoid listview_set_mouse_activated_cb(listview *lv,\n                                     listview_mouse_activated_cb cb,\n                                     void *udata) {\n  if (lv) {\n    lv->mouse_activated = cb;\n    lv->mouse_activated_data = udata;\n  }\n}\n\nvoid listview_set_max_lines(listview *lv, unsigned int max_lines) {\n  if (lv) {\n    lv->max_displayed_lines = max_lines;\n  }\n}\n\ngboolean listview_get_fixed_num_lines(listview *lv) {\n  if (lv) {\n    return lv->fixed_num_lines;\n  }\n  return FALSE;\n}\nvoid listview_set_fixed_num_lines(listview *lv) {\n  if (lv) {\n    lv->fixed_num_lines = TRUE;\n  }\n}\n\nvoid listview_set_ellipsize(listview *lv, PangoEllipsizeMode mode) {\n  if (lv) {\n    lv->emode = mode;\n    for (unsigned int i = 0; i < lv->cur_elements; i++) {\n      textbox_set_ellipsize(lv->boxes[i].textbox, lv->emode);\n    }\n  }\n}\n\nvoid listview_toggle_ellipsizing(listview *lv) {\n  if (lv) {\n    PangoEllipsizeMode mode = lv->emode;\n    if (mode == PANGO_ELLIPSIZE_START) {\n      mode = PANGO_ELLIPSIZE_MIDDLE;\n    } else if (mode == PANGO_ELLIPSIZE_MIDDLE) {\n      mode = PANGO_ELLIPSIZE_END;\n    } else if (mode == PANGO_ELLIPSIZE_END) {\n      mode = PANGO_ELLIPSIZE_START;\n    }\n    lv->emode = mode;\n    for (unsigned int i = 0; i < lv->cur_elements; i++) {\n      textbox_set_ellipsize(lv->boxes[i].textbox, mode);\n    }\n  }\n}\n\nvoid listview_set_filtered(listview *lv, gboolean filtered) {\n  if (lv) {\n    lv->filtered = filtered;\n  }\n}\n\nvoid listview_set_selection_changed_callback(\n    listview *lv, listview_selection_changed_callback cb, void *udata) {\n  lv->sc_callback = cb;\n  lv->sc_udata = udata;\n}\n"
  },
  {
    "path": "source/widgets/scrollbar.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"widgets/scrollbar.h\"\n#include \"widgets/icon.h\"\n#include \"widgets/listview.h\"\n#include \"widgets/textbox.h\"\n#include <glib.h>\n\n#include \"theme.h\"\n\n#include <math.h>\n\n/** The default width of the scrollbar */\n#define DEFAULT_SCROLLBAR_WIDTH 8\n\nstatic void scrollbar_draw(widget *, cairo_t *);\nstatic void scrollbar_free(widget *);\n\nstatic int scrollbar_get_desired_height(widget *wid,\n                                        G_GNUC_UNUSED const int width) {\n  // Want height we are.\n  return wid->h;\n}\n\n// TODO\n// This should behave more like a real scrollbar.\nguint scrollbar_scroll_get_line(const scrollbar *sb, int y) {\n  y -= sb->widget.border.top.base.distance;\n  if (y < 0) {\n    return 0;\n  }\n\n  if (y > sb->widget.h) {\n    return sb->length - 1;\n  }\n\n  short r =\n      (sb->length * sb->widget.h) / ((double)(sb->length + sb->pos_length));\n  short handle = sb->widget.h - r;\n  double sec = ((r) / (double)(sb->length - 1));\n  short half_handle = handle / 2;\n  y -= half_handle;\n  y = MIN(MAX(0, y), sb->widget.h - 2 * half_handle);\n\n  unsigned int sel = round((y) / sec);\n  return MIN(sel, sb->length - 1);\n}\n\nstatic void scrollbar_scroll(scrollbar *sb, int y) {\n  listview_set_selected((listview *)sb->widget.parent,\n                        scrollbar_scroll_get_line(sb, y));\n}\n\nstatic WidgetTriggerActionResult\nscrollbar_trigger_action(widget *wid, MouseBindingMouseDefaultAction action,\n                         G_GNUC_UNUSED gint x, gint y,\n                         G_GNUC_UNUSED void *user_data) {\n  scrollbar *sb = (scrollbar *)wid;\n  switch (action) {\n  case MOUSE_CLICK_DOWN:\n    return WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN;\n  case MOUSE_CLICK_UP:\n    scrollbar_scroll(sb, y);\n    return WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END;\n  case MOUSE_DCLICK_DOWN:\n  case MOUSE_DCLICK_UP:\n    break;\n  }\n  return FALSE;\n}\n\nstatic gboolean scrollbar_motion_notify(widget *wid, G_GNUC_UNUSED gint x,\n                                        gint y) {\n  scrollbar *sb = (scrollbar *)wid;\n  scrollbar_scroll(sb, y);\n  return TRUE;\n}\n\nscrollbar *scrollbar_create(widget *parent, const char *name) {\n  scrollbar *sb = g_malloc0(sizeof(scrollbar));\n  widget_init(WIDGET(sb), parent, WIDGET_TYPE_SCROLLBAR, name);\n  sb->widget.x = 0;\n  sb->widget.y = 0;\n  sb->width = rofi_theme_get_distance(WIDGET(sb), \"handle-width\",\n                                      DEFAULT_SCROLLBAR_WIDTH);\n  int width = distance_get_pixel(sb->width, ROFI_ORIENTATION_HORIZONTAL);\n  sb->widget.w = widget_padding_get_padding_width(WIDGET(sb)) + width;\n  sb->widget.h = widget_padding_get_padding_height(WIDGET(sb));\n\n  sb->widget.draw = scrollbar_draw;\n  sb->widget.free = scrollbar_free;\n  sb->widget.trigger_action = scrollbar_trigger_action;\n  sb->widget.motion_notify = scrollbar_motion_notify;\n  sb->widget.get_desired_height = scrollbar_get_desired_height;\n\n  sb->length = 10;\n  sb->pos = 0;\n  sb->pos_length = 4;\n\n  return sb;\n}\n\nstatic void scrollbar_free(widget *wid) {\n  scrollbar *sb = (scrollbar *)wid;\n  g_free(sb);\n}\n\nvoid scrollbar_set_max_value(scrollbar *sb, unsigned int max) {\n  if (sb != NULL) {\n    sb->length = MAX(1u, max);\n  }\n}\n\nvoid scrollbar_set_handle(scrollbar *sb, unsigned int pos) {\n  if (sb != NULL) {\n    sb->pos = MIN(sb->length, pos);\n  }\n}\n\nvoid scrollbar_set_handle_length(scrollbar *sb, unsigned int pos_length) {\n  if (sb != NULL) {\n    sb->pos_length = MIN(sb->length, MAX(1u, pos_length));\n  }\n}\n\n/**\n * The range is the height - handle length.\n * r = h - handle;\n * handle is the element length of the handle* length of one element.\n * handle =  r / ( num ) * hl\n *\n * r = h - r / ( num) *hl\n * r*num = num*h - r*hl\n * r*num+r*hl = num*h;\n * r ( num+hl ) = num*h\n * r = (num*h)/(num+hl)\n */\nstatic void scrollbar_draw(widget *wid, cairo_t *draw) {\n  scrollbar *sb = (scrollbar *)wid;\n  double wh = widget_padding_get_remaining_height(wid);\n  // Calculate position and size.\n  double r = (sb->length * wh) / ((double)(sb->length + sb->pos_length));\n  unsigned int handle = wid->h - r;\n  double sec = ((r) / (double)(sb->length - 1));\n  unsigned int height = handle;\n  unsigned int y = sb->pos * sec;\n  // Set max pos.\n  y = MIN(y, wh - handle);\n  // Never go out of bar.\n  height = MAX(2, height);\n  // Cap length;\n  rofi_theme_get_color(WIDGET(sb), \"handle-color\", draw);\n\n  if (rofi_theme_get_boolean(WIDGET(sb), \"handle-rounded-corners\", FALSE)) {\n    float x = widget_padding_get_left(wid);\n    float width = widget_padding_get_remaining_width(wid);\n\n    float radius = ((width < height) ? width : height) /\n                   2; // Limit radius to prevent overlap\n\n    // Draw rounded rectangle\n    cairo_new_sub_path(draw);\n    cairo_arc(draw, x + width - radius, y + radius, radius, -G_PI_2, 0);\n    cairo_arc(draw, x + width - radius, y + height - radius, radius, 0, G_PI_2);\n    cairo_arc(draw, x + radius, y + height - radius, radius, G_PI_2, G_PI);\n    cairo_arc(draw, x + radius, y + radius, radius, G_PI, 1.5 * G_PI);\n    cairo_close_path(draw);\n\n    cairo_fill(draw);\n  } else {\n    cairo_rectangle(draw, widget_padding_get_left(wid),\n                    widget_padding_get_top(wid) + y,\n                    widget_padding_get_remaining_width(wid), height);\n    cairo_fill(draw);\n  }\n}\n"
  },
  {
    "path": "source/widgets/textbox.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"config.h\"\n\n#include \"helper-theme.h\"\n#include \"helper.h\"\n#include \"keyb.h\"\n#include \"mode.h\"\n#include \"timings.h\"\n#include \"view.h\"\n#include \"widgets/textbox.h\"\n#include <ctype.h>\n#include <glib.h>\n#include <math.h>\n#include <string.h>\n\n#include \"theme.h\"\n\nstatic void textbox_draw(widget *, cairo_t *);\nstatic void textbox_free(widget *);\nstatic int textbox_get_width(widget *);\nstatic int _textbox_get_height(widget *);\nstatic void __textbox_update_pango_text(textbox *tb);\n\n/** Default pango context */\nstatic PangoContext *p_context = NULL;\n/** The pango font metrics */\nstatic PangoFontMetrics *p_metrics = NULL;\n\n/** Default tbfc */\nstatic TBFontConfig *tbfc_default = NULL;\n\n/** HashMap of previously parsed font descriptions. */\nstatic GHashTable *tbfc_cache = NULL;\n\nstatic gboolean textbox_blink(gpointer data) {\n  textbox *tb = (textbox *)data;\n  if (tb->blink < 2) {\n    tb->blink = !tb->blink;\n    widget_queue_redraw(WIDGET(tb));\n    rofi_view_queue_redraw();\n  } else {\n    tb->blink--;\n  }\n  return TRUE;\n}\n\nstatic void textbox_resize(widget *wid, short w, short h) {\n  textbox *tb = (textbox *)wid;\n  textbox_moveresize(tb, tb->widget.x, tb->widget.y, w, h);\n}\nstatic int textbox_get_desired_height(widget *wid, const int width) {\n  textbox *tb = (textbox *)wid;\n  if ((tb->flags & TB_AUTOHEIGHT) == 0) {\n    return tb->widget.h;\n  }\n  if (tb->changed) {\n    __textbox_update_pango_text(tb);\n  }\n  int old_width = pango_layout_get_width(tb->layout);\n  pango_layout_set_width(\n      tb->layout,\n      PANGO_SCALE * (width - widget_padding_get_padding_width(WIDGET(tb))));\n\n  int height =\n      textbox_get_estimated_height(tb, pango_layout_get_line_count(tb->layout));\n  pango_layout_set_width(tb->layout, old_width);\n  return height;\n}\n\nstatic WidgetTriggerActionResult\ntextbox_editable_trigger_action(widget *wid,\n                                MouseBindingMouseDefaultAction action, gint x,\n                                gint y, G_GNUC_UNUSED void *user_data) {\n  textbox *tb = (textbox *)wid;\n  switch (action) {\n  case MOUSE_CLICK_DOWN: {\n    gint i;\n    // subtract padding on left.\n    x -= widget_padding_get_left(wid);\n    gint max = textbox_get_font_width(tb);\n    // Right of text, move to end.\n    if (x >= max) {\n      textbox_cursor_end(tb);\n    } else if (x > 0) {\n      // If in range, get index.\n      pango_layout_xy_to_index(tb->layout, x * PANGO_SCALE, y * PANGO_SCALE, &i,\n                               NULL);\n      textbox_cursor(tb, i);\n    }\n    return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n  }\n  case MOUSE_CLICK_UP:\n  case MOUSE_DCLICK_DOWN:\n  case MOUSE_DCLICK_UP:\n    break;\n  }\n  return WIDGET_TRIGGER_ACTION_RESULT_IGNORED;\n}\n\nstatic void textbox_initialize_font(textbox *tb) {\n  tb->tbfc = tbfc_default;\n  const char *font = rofi_theme_get_string(WIDGET(tb), \"font\", NULL);\n  if (font) {\n    TBFontConfig *tbfc = g_hash_table_lookup(tbfc_cache, font);\n    if (tbfc == NULL) {\n      tbfc = g_malloc0(sizeof(TBFontConfig));\n      tbfc->pfd = pango_font_description_from_string(font);\n      if (helper_validate_font(tbfc->pfd, font)) {\n        tbfc->metrics = pango_context_get_metrics(p_context, tbfc->pfd, NULL);\n\n        PangoLayout *layout = pango_layout_new(p_context);\n        pango_layout_set_font_description(layout, tbfc->pfd);\n        pango_layout_set_text(layout, \"aAjb\", -1);\n        PangoRectangle rect;\n        pango_layout_get_pixel_extents(layout, NULL, &rect);\n        tbfc->height = rect.y + rect.height;\n\n        // Try to find height from font. Might be slow?\n        TICK_N(\"Get font height\");\n        PangoFont *context_font = pango_context_load_font(p_context, tbfc->pfd);\n        if (context_font) {\n          PangoFontMetrics *fm = pango_font_get_metrics(context_font, NULL);\n          if (fm) {\n            int h = pango_font_metrics_get_height(fm) / PANGO_SCALE;\n            if (h > 0) {\n              tbfc->height = h;\n            }\n            pango_font_metrics_unref(fm);\n          }\n          g_object_unref(context_font);\n        }\n        TICK_N(\"Get font height\");\n        g_object_unref(layout);\n\n        // Cast away consts. (*yuck*) because table_insert does not know it is\n        // const.\n        g_hash_table_insert(tbfc_cache, (char *)font, tbfc);\n      } else {\n        pango_font_description_free(tbfc->pfd);\n        g_free(tbfc);\n        tbfc = NULL;\n      }\n    }\n    if (tbfc) {\n      // Update for used font.\n      pango_layout_set_font_description(tb->layout, tbfc->pfd);\n      tb->tbfc = tbfc;\n    }\n  }\n}\n\nstatic void textbox_tab_stops(textbox *tb) {\n  GList *dists = rofi_theme_get_list_distance(WIDGET(tb), \"tab-stops\");\n\n  if (dists != NULL) {\n    PangoTabArray *tabs = pango_tab_array_new(g_list_length(dists), TRUE);\n\n    int i = 0, ppx = 0;\n    for (const GList *iter = g_list_first(dists); iter != NULL;\n         iter = g_list_next(iter), i++) {\n      const RofiDistance *dist = iter->data;\n\n      int px = distance_get_pixel(*dist, ROFI_ORIENTATION_HORIZONTAL);\n      if (px <= ppx) {\n        continue;\n      }\n      pango_tab_array_set_tab(tabs, i, PANGO_TAB_LEFT, px);\n      ppx = px;\n    }\n    pango_layout_set_tabs(tb->layout, tabs);\n\n    pango_tab_array_free(tabs);\n    g_list_free_full(dists, g_free);\n  }\n}\n\ntextbox *textbox_create(widget *parent, WidgetType type, const char *name,\n                        TextboxFlags flags, TextBoxFontType tbft,\n                        const char *text, double xalign, double yalign) {\n  textbox *tb = g_slice_new0(textbox);\n\n  widget_init(WIDGET(tb), parent, type, name);\n\n  tb->widget.draw = textbox_draw;\n  tb->widget.free = textbox_free;\n  tb->widget.resize = textbox_resize;\n  tb->widget.get_width = textbox_get_width;\n  tb->widget.get_height = _textbox_get_height;\n  tb->widget.get_desired_height = textbox_get_desired_height;\n  tb->widget.get_desired_width = textbox_get_desired_width;\n  tb->flags = flags;\n  tb->emode = PANGO_ELLIPSIZE_END;\n\n  tb->changed = FALSE;\n\n  tb->layout = pango_layout_new(p_context);\n  textbox_font(tb, tbft);\n\n  textbox_initialize_font(tb);\n  textbox_tab_stops(tb);\n\n  if ((tb->flags & TB_WRAP) == TB_WRAP) {\n    pango_layout_set_wrap(tb->layout, PANGO_WRAP_WORD_CHAR);\n  }\n\n  // Allow overriding of markup.\n  if (rofi_theme_get_boolean(WIDGET(tb), \"markup\",\n                             (tb->flags & TB_MARKUP) == TB_MARKUP)) {\n    tb->flags |= TB_MARKUP;\n  } else {\n    tb->flags &= (~TB_MARKUP);\n  }\n\n  const char *txt = rofi_theme_get_string(WIDGET(tb), \"str\", text);\n  if (txt == NULL || (*txt) == '\\0') {\n    txt = rofi_theme_get_string(WIDGET(tb), \"content\", text);\n  }\n  const char *placeholder =\n      rofi_theme_get_string(WIDGET(tb), \"placeholder\", NULL);\n  if (placeholder) {\n    if (rofi_theme_get_boolean(WIDGET(tb), \"placeholder-markup\", FALSE)) {\n      tb->placeholder = g_strdup(placeholder);\n    } else {\n      tb->placeholder = g_markup_escape_text(placeholder, -1);\n    }\n  }\n\n  const char *password_mask_char =\n      rofi_theme_get_string(WIDGET(tb), \"password-mask\", NULL);\n  if (password_mask_char == NULL || (*password_mask_char) == '\\0') {\n    tb->password_mask_char = \"*\";\n  } else {\n    tb->password_mask_char = password_mask_char;\n  }\n\n  textbox_text(tb, txt ? txt : \"\");\n  textbox_cursor_end(tb);\n\n  tb->blink_timeout = 0;\n  tb->blink = 1;\n  if ((tb->flags & TB_EDITABLE) == TB_EDITABLE) {\n    if (rofi_theme_get_boolean(WIDGET(tb), \"blink\", TRUE)) {\n      tb->blink_timeout = g_timeout_add(1200, textbox_blink, tb);\n    }\n    tb->widget.trigger_action = textbox_editable_trigger_action;\n  }\n\n  tb->yalign = rofi_theme_get_double(WIDGET(tb), \"vertical-align\", yalign);\n  tb->yalign = MAX(0, MIN(1.0, tb->yalign));\n  tb->xalign = rofi_theme_get_double(WIDGET(tb), \"horizontal-align\", xalign);\n  tb->xalign = MAX(0, MIN(1.0, tb->xalign));\n\n  if (tb->xalign < 0.2) {\n    pango_layout_set_alignment(tb->layout, PANGO_ALIGN_LEFT);\n  } else if (tb->xalign < 0.8) {\n    pango_layout_set_alignment(tb->layout, PANGO_ALIGN_CENTER);\n  } else {\n    pango_layout_set_alignment(tb->layout, PANGO_ALIGN_RIGHT);\n  }\n  // auto height/width modes get handled here\n  // UPDATE: don't autoheight here, as there is no width set.\n  // so no height can be determined and might result into  crash.\n  // textbox_moveresize(tb, tb->widget.x, tb->widget.y, tb->widget.w,\n  //                   tb->widget.h);\n\n  return tb;\n}\n\n/**\n * State names used for theming.\n */\nconst char *const theme_prop_names[][3] = {\n    /** Normal row */\n    {\"normal.normal\", \"selected.normal\", \"alternate.normal\"},\n    /** Urgent row */\n    {\"normal.urgent\", \"selected.urgent\", \"alternate.urgent\"},\n    /** Active row */\n    {\"normal.active\", \"selected.active\", \"alternate.active\"},\n};\n\nvoid textbox_font(textbox *tb, TextBoxFontType tbft) {\n  TextBoxFontType t = tbft & STATE_MASK;\n  if (tb == NULL) {\n    return;\n  }\n  // ACTIVE has priority over URGENT if both set.\n  if (t == (URGENT | ACTIVE)) {\n    t = ACTIVE;\n  }\n  switch ((tbft & FMOD_MASK)) {\n  case HIGHLIGHT:\n    widget_set_state(WIDGET(tb), theme_prop_names[t][1]);\n    break;\n  case ALT:\n    widget_set_state(WIDGET(tb), theme_prop_names[t][2]);\n    break;\n  default:\n    widget_set_state(WIDGET(tb), theme_prop_names[t][0]);\n    break;\n  }\n  if (tb->tbft != tbft || tb->widget.state == NULL) {\n    widget_queue_redraw(WIDGET(tb));\n  }\n  tb->tbft = tbft;\n}\n\n/**\n * @param tb The textbox object.\n *\n * Update the pango layout's text. It does this depending on the\n * textbox flags.\n */\nstatic void __textbox_update_pango_text(textbox *tb) {\n  pango_layout_set_attributes(tb->layout, NULL);\n  if (tb->placeholder && (tb->text == NULL || tb->text[0] == 0)) {\n    tb->show_placeholder = TRUE;\n    pango_layout_set_markup(tb->layout, tb->placeholder, -1);\n    return;\n  }\n  tb->show_placeholder = FALSE;\n  if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {\n    size_t text_len = g_utf8_strlen(tb->text, -1);\n    size_t mask_len = strlen(tb->password_mask_char);\n    char string[text_len * mask_len + 1];\n    for (size_t offset = 0; offset < text_len * mask_len; offset += mask_len) {\n      memcpy(string + offset, tb->password_mask_char, mask_len);\n    }\n    string[text_len * mask_len] = '\\0';\n    pango_layout_set_text(tb->layout, string, -1);\n  } else if (tb->flags & TB_MARKUP || tb->tbft & MARKUP) {\n    pango_layout_set_markup(tb->layout, tb->text, -1);\n  } else {\n    pango_layout_set_text(tb->layout, tb->text, -1);\n  }\n  if (tb->text) {\n    RofiHighlightColorStyle th = {0, {0.0, 0.0, 0.0, 0.0}};\n    th = rofi_theme_get_highlight(WIDGET(tb), \"text-transform\", th);\n    if (th.style != 0) {\n      PangoAttrList *list = pango_attr_list_new();\n      helper_token_match_set_pango_attr_on_style(list, 0, G_MAXUINT, th);\n      pango_layout_set_attributes(tb->layout, list);\n    }\n  }\n}\nconst char *textbox_get_visible_text(const textbox *tb) {\n  if (tb == NULL) {\n    return NULL;\n  }\n  return pango_layout_get_text(tb->layout);\n}\nPangoAttrList *textbox_get_pango_attributes(textbox *tb) {\n  if (tb == NULL) {\n    return NULL;\n  }\n  return pango_layout_get_attributes(tb->layout);\n}\nvoid textbox_set_pango_attributes(textbox *tb, PangoAttrList *list) {\n  if (tb == NULL) {\n    return;\n  }\n  pango_layout_set_attributes(tb->layout, list);\n}\n\nchar *textbox_get_text(const textbox *tb) {\n  if (tb->text == NULL) {\n    return g_strdup(\"\");\n  }\n  return g_strdup(tb->text);\n}\nint textbox_get_cursor(const textbox *tb) {\n  if (tb) {\n    return tb->cursor;\n  }\n  return 0;\n}\n// set the default text to display\nvoid textbox_text(textbox *tb, const char *text) {\n  if (tb == NULL) {\n    return;\n  }\n  g_free(tb->text);\n  const gchar *last_pointer = NULL;\n\n  if (text == NULL) {\n    tb->text = g_strdup(\"Invalid string.\");\n  } else {\n    if (g_utf8_validate(text, -1, &last_pointer)) {\n      tb->text = g_strdup(text);\n    } else {\n      if (last_pointer != NULL) {\n        // Copy string up to invalid character.\n        tb->text = g_strndup(text, (last_pointer - text));\n      } else {\n        tb->text = g_strdup(\"Invalid UTF-8 string.\");\n      }\n    }\n  }\n  __textbox_update_pango_text(tb);\n  if (tb->flags & TB_AUTOWIDTH) {\n    textbox_moveresize(tb, tb->widget.x, tb->widget.y, tb->widget.w,\n                       tb->widget.h);\n    if (WIDGET(tb)->parent) {\n      widget_update(WIDGET(tb)->parent);\n    }\n  }\n\n  tb->cursor = MAX(0, MIN((int)g_utf8_strlen(tb->text, -1), tb->cursor));\n  widget_queue_redraw(WIDGET(tb));\n}\n\n// within the parent handled auto width/height modes\nvoid textbox_moveresize(textbox *tb, int x, int y, int w, int h) {\n  if (tb->flags & TB_AUTOWIDTH) {\n    pango_layout_set_width(tb->layout, -1);\n    w = textbox_get_font_width(tb) +\n        widget_padding_get_padding_width(WIDGET(tb));\n  } else {\n    // set ellipsize\n    if ((tb->flags & TB_EDITABLE) == TB_EDITABLE) {\n      pango_layout_set_ellipsize(tb->layout, PANGO_ELLIPSIZE_MIDDLE);\n    } else if ((tb->flags & TB_WRAP) != TB_WRAP) {\n      pango_layout_set_ellipsize(tb->layout, tb->emode);\n    } else {\n      pango_layout_set_ellipsize(tb->layout, PANGO_ELLIPSIZE_NONE);\n    }\n  }\n\n  if (tb->flags & TB_AUTOHEIGHT) {\n    // Width determines height!\n    int padding = widget_padding_get_padding_width(WIDGET(tb));\n    int tw = MAX(1 + padding, w);\n    pango_layout_set_width(tb->layout, PANGO_SCALE * (tw - padding));\n    int hd = textbox_get_height(tb);\n    h = MAX(hd, h);\n  }\n\n  if (x != tb->widget.x || y != tb->widget.y || w != tb->widget.w ||\n      h != tb->widget.h) {\n    tb->widget.x = x;\n    tb->widget.y = y;\n    tb->widget.h = MAX(1, h);\n    tb->widget.w = MAX(1, w);\n  }\n\n  // We always want to update this\n  pango_layout_set_width(\n      tb->layout, PANGO_SCALE * (tb->widget.w -\n                                 widget_padding_get_padding_width(WIDGET(tb))));\n  widget_queue_redraw(WIDGET(tb));\n}\n\n// will also unmap the window if still displayed\nstatic void textbox_free(widget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n  textbox *tb = (textbox *)wid;\n  if (tb->blink_timeout > 0) {\n    g_source_remove(tb->blink_timeout);\n    tb->blink_timeout = 0;\n  }\n  g_free(tb->text);\n\n  g_free(tb->placeholder);\n  if (tb->layout != NULL) {\n    g_object_unref(tb->layout);\n  }\n\n  g_slice_free(textbox, tb);\n}\n\nstatic void textbox_draw(widget *wid, cairo_t *draw) {\n  if (wid == NULL) {\n    return;\n  }\n  textbox *tb = (textbox *)wid;\n\n  if (tb->changed) {\n    __textbox_update_pango_text(tb);\n  }\n\n  // Skip the side MARGIN on the X axis.\n  int x;\n  int top = widget_padding_get_top(WIDGET(tb));\n  int y = (pango_font_metrics_get_ascent(tb->tbfc->metrics) -\n           pango_layout_get_baseline(tb->layout)) /\n          PANGO_SCALE;\n  int line_width = 0, line_height = 0;\n  // Get actual width.\n  pango_layout_get_pixel_size(tb->layout, &line_width, &line_height);\n\n  if (tb->yalign > 0.001) {\n    int bottom = widget_padding_get_bottom(WIDGET(tb));\n    top = (tb->widget.h - bottom - line_height - top) * tb->yalign + top;\n  }\n  y += top;\n\n  // Set ARGB\n  // NOTE: cairo operator must be OVER at this moment,\n  // to not break subpixel text rendering.\n\n  cairo_set_source_rgb(draw, 0.0, 0.0, 0.0);\n  // use text color as fallback for themes that don't specify the cursor color\n  rofi_theme_get_color(WIDGET(tb), \"text-color\", draw);\n\n  {\n    int rem =\n        MAX(0, tb->widget.w - widget_padding_get_padding_width(WIDGET(tb)) -\n                   line_width);\n    switch (pango_layout_get_alignment(tb->layout)) {\n    case PANGO_ALIGN_CENTER:\n      x = rem * (tb->xalign - 0.5);\n      break;\n    case PANGO_ALIGN_RIGHT:\n      x = rem * (tb->xalign - 1.0);\n      break;\n    default:\n      x = rem * tb->xalign;\n      break;\n    }\n    x += widget_padding_get_left(WIDGET(tb));\n  }\n\n  // draw the cursor\n  if (tb->flags & TB_EDITABLE) {\n    // We want to place the cursor based on the text shown.\n    const char *text = pango_layout_get_text(tb->layout);\n    // hide the cursor, if no text is entered and hide-empty-cursor is set to\n    // true\n    if (!(tb->text[0] == '\\0' &&\n          rofi_theme_get_boolean(WIDGET(tb), \"hide-cursor-on-empty\", FALSE) ==\n              TRUE)) {\n      // Clamp the position, should not be needed, but we are paranoid.\n      size_t cursor_offset;\n\n      if ((tb->flags & TB_PASSWORD) == TB_PASSWORD) {\n        // Calculate cursor position based on mask length\n        size_t mask_len = strlen(tb->password_mask_char);\n        cursor_offset = MIN(tb->cursor * mask_len, strlen(text));\n      } else {\n        cursor_offset = MIN(tb->cursor, g_utf8_strlen(text, -1));\n        // convert to byte location.\n        char *offset = g_utf8_offset_to_pointer(text, cursor_offset);\n        cursor_offset = offset - text;\n      }\n      PangoRectangle pos;\n      pango_layout_get_cursor_pos(tb->layout, cursor_offset, &pos, NULL);\n      int cursor_x = pos.x / PANGO_SCALE;\n      int cursor_y = pos.y / PANGO_SCALE;\n      int cursor_height = pos.height / PANGO_SCALE;\n      RofiDistance cursor_width =\n          rofi_theme_get_distance(WIDGET(tb), \"cursor-width\", 2);\n      int cursor_pixel_width =\n          distance_get_pixel(cursor_width, ROFI_ORIENTATION_HORIZONTAL);\n      if ((x + cursor_x) != tb->cursor_x_pos) {\n        tb->cursor_x_pos = x + cursor_x;\n      }\n      if (tb->blink) {\n        // This save/restore state is necessary to render the text in the\n        // correct color when `cursor-color` is set\n        cairo_save(draw);\n        // use text color as fallback for themes that don't specify the cursor\n        // color\n        rofi_theme_get_color(WIDGET(tb), \"cursor-color\", draw);\n        cairo_rectangle(draw, x + cursor_x, y + cursor_y, cursor_pixel_width,\n                        cursor_height);\n        if (rofi_theme_get_boolean(WIDGET(tb), \"cursor-outline\", FALSE)) {\n          cairo_fill_preserve(draw);\n          rofi_theme_get_color(WIDGET(tb), \"cursor-outline-color\", draw);\n          double width =\n              rofi_theme_get_double(WIDGET(tb), \"cursor-outline-width\", 0.5);\n          cairo_set_line_width(draw, width);\n          cairo_stroke(draw);\n        } else {\n          cairo_fill(draw);\n        }\n        cairo_restore(draw);\n      }\n    }\n  }\n\n  // draw the text\n  cairo_save(draw);\n  double x1, y1, x2, y2;\n  cairo_clip_extents(draw, &x1, &y1, &x2, &y2);\n  cairo_reset_clip(draw);\n  cairo_rectangle(draw, x1, y1, x2 - x1, y2 - y1);\n  cairo_clip(draw);\n\n  gboolean show_outline;\n  if (tb->show_placeholder) {\n    rofi_theme_get_color(WIDGET(tb), \"placeholder-color\", draw);\n    show_outline = FALSE;\n  } else {\n    show_outline = rofi_theme_get_boolean(WIDGET(tb), \"text-outline\", FALSE);\n  }\n  cairo_move_to(draw, x, top);\n  pango_cairo_show_layout(draw, tb->layout);\n\n  if (show_outline) {\n    rofi_theme_get_color(WIDGET(tb), \"text-outline-color\", draw);\n    double width = rofi_theme_get_double(WIDGET(tb), \"text-outline-width\", 0.5);\n    cairo_move_to(draw, x, top);\n    pango_cairo_layout_path(draw, tb->layout);\n    cairo_set_line_width(draw, width);\n    cairo_stroke(draw);\n  }\n\n  cairo_restore(draw);\n}\n\n// cursor handling for edit mode\nvoid textbox_cursor(textbox *tb, int pos) {\n  if (tb == NULL) {\n    return;\n  }\n  int length = (tb->text == NULL) ? 0 : g_utf8_strlen(tb->text, -1);\n  tb->cursor = MAX(0, MIN(length, pos));\n  // Stop blink!\n  tb->blink = 3;\n  widget_queue_redraw(WIDGET(tb));\n}\n\n/**\n * @param tb Handle to the textbox\n *\n * Move cursor one position forward.\n *\n * @returns if cursor was moved.\n */\nstatic int textbox_cursor_inc(textbox *tb) {\n  int old = tb->cursor;\n  textbox_cursor(tb, tb->cursor + 1);\n  return old != tb->cursor;\n}\n\n/**\n * @param tb Handle to the textbox\n *\n * Move cursor one position backward.\n *\n * @returns if cursor was moved.\n */\nstatic int textbox_cursor_dec(textbox *tb) {\n  int old = tb->cursor;\n  textbox_cursor(tb, tb->cursor - 1);\n  return old != tb->cursor;\n}\n\n// Move word right\nstatic void textbox_cursor_inc_word(textbox *tb) {\n  if (tb->text == NULL) {\n    return;\n  }\n  // Find word boundaries, with pango_Break?\n  gchar *c = g_utf8_offset_to_pointer(tb->text, tb->cursor);\n  while ((c = g_utf8_next_char(c))) {\n    gunichar uc = g_utf8_get_char(c);\n    GUnicodeBreakType bt = g_unichar_break_type(uc);\n    if ((bt == G_UNICODE_BREAK_ALPHABETIC ||\n         bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC ||\n         bt == G_UNICODE_BREAK_QUOTATION)) {\n      break;\n    }\n  }\n  if (c == NULL || *c == '\\0') {\n    return;\n  }\n  while ((c = g_utf8_next_char(c))) {\n    gunichar uc = g_utf8_get_char(c);\n    GUnicodeBreakType bt = g_unichar_break_type(uc);\n    if (!(bt == G_UNICODE_BREAK_ALPHABETIC ||\n          bt == G_UNICODE_BREAK_HEBREW_LETTER ||\n          bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION)) {\n      break;\n    }\n  }\n  int index = g_utf8_pointer_to_offset(tb->text, c);\n  textbox_cursor(tb, index);\n}\n// move word left\nstatic void textbox_cursor_dec_word(textbox *tb) {\n  // Find word boundaries, with pango_Break?\n  gchar *n;\n  gchar *c = g_utf8_offset_to_pointer(tb->text, tb->cursor);\n  while ((c = g_utf8_prev_char(c)) && c != tb->text) {\n    gunichar uc = g_utf8_get_char(c);\n    GUnicodeBreakType bt = g_unichar_break_type(uc);\n    if ((bt == G_UNICODE_BREAK_ALPHABETIC ||\n         bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC ||\n         bt == G_UNICODE_BREAK_QUOTATION)) {\n      break;\n    }\n  }\n  if (c != tb->text) {\n    while ((n = g_utf8_prev_char(c))) {\n      gunichar uc = g_utf8_get_char(n);\n      GUnicodeBreakType bt = g_unichar_break_type(uc);\n      if (!(bt == G_UNICODE_BREAK_ALPHABETIC ||\n            bt == G_UNICODE_BREAK_HEBREW_LETTER ||\n            bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION)) {\n        break;\n      }\n      c = n;\n      if (n == tb->text) {\n        break;\n      }\n    }\n  }\n  int index = g_utf8_pointer_to_offset(tb->text, c);\n  textbox_cursor(tb, index);\n}\n\n// end of line\nvoid textbox_cursor_end(textbox *tb) {\n  if (tb->text == NULL) {\n    tb->cursor = 0;\n    widget_queue_redraw(WIDGET(tb));\n    return;\n  }\n  tb->cursor = (int)g_utf8_strlen(tb->text, -1);\n  widget_queue_redraw(WIDGET(tb));\n  // Stop blink!\n  tb->blink = 2;\n}\n\n// insert text\nvoid textbox_insert(textbox *tb, const int char_pos, const char *str,\n                    const int slen) {\n  if (tb == NULL) {\n    return;\n  }\n  char *c = g_utf8_offset_to_pointer(tb->text, char_pos);\n  int pos = c - tb->text;\n  int len = (int)strlen(tb->text);\n  pos = MAX(0, MIN(len, pos));\n  // expand buffer\n  tb->text = g_realloc(tb->text, len + slen + 1);\n  // move everything after cursor upward\n  char *at = tb->text + pos;\n  memmove(at + slen, at, len - pos + 1);\n  // insert new str\n  memmove(at, str, slen);\n\n  // Set modified, lay out need te be redrawn\n  // Stop blink!\n  tb->blink = 2;\n  tb->changed = TRUE;\n}\n\n// remove text\nvoid textbox_delete(textbox *tb, int pos, int dlen) {\n  if (tb == NULL) {\n    return;\n  }\n  int len = g_utf8_strlen(tb->text, -1);\n  if (len == pos) {\n    return;\n  }\n  pos = MAX(0, MIN(len, pos));\n  if ((pos + dlen) > len) {\n    dlen = len - dlen;\n  }\n  // move everything after pos+dlen down\n  char *start = g_utf8_offset_to_pointer(tb->text, pos);\n  char *end = g_utf8_offset_to_pointer(tb->text, pos + dlen);\n  // Move remainder + closing \\0\n  memmove(start, end, (tb->text + strlen(tb->text)) - end + 1);\n  if (tb->cursor >= pos && tb->cursor < (pos + dlen)) {\n    tb->cursor = pos;\n  } else if (tb->cursor >= (pos + dlen)) {\n    tb->cursor -= dlen;\n  }\n  // Set modified, lay out need te be redrawn\n  // Stop blink!\n  tb->blink = 2;\n  tb->changed = TRUE;\n}\n\n/**\n * @param tb Handle to the textbox\n *\n * Delete character after cursor.\n */\nstatic void textbox_cursor_del(textbox *tb) {\n  if (tb == NULL || tb->text == NULL) {\n    return;\n  }\n  textbox_delete(tb, tb->cursor, 1);\n}\n\n/**\n * @param tb Handle to the textbox\n *\n * Delete character before cursor.\n */\nstatic void textbox_cursor_bkspc(textbox *tb) {\n  if (tb && tb->cursor > 0) {\n    textbox_cursor_dec(tb);\n    textbox_cursor_del(tb);\n  }\n}\n\n/**\n * @param tb Handle to the textbox\n *\n * Transpose the two characters before the cursor.\n */\nstatic void textbox_transpose_chars(textbox *tb) {\n  // Need to have more then 2 characters in front of the cursor.\n  if (tb == NULL || tb->cursor < 2) {\n    return;\n  }\n  // Find pointer to cursor.\n  gchar *cursor_ptr = g_utf8_offset_to_pointer(tb->text, tb->cursor);\n  if ( cursor_ptr == NULL ){\n    // We should never reach this.\n    g_warning(\"Invalid cursor index detected.\");\n    return;\n  }\n  // Find previous character pointer. (1)\n  gchar *second_char_ptr = g_utf8_find_prev_char(tb->text, cursor_ptr);\n  if (second_char_ptr == NULL) {\n    // Failed to move cursor one back, so we cannot swap.\n    return;\n  }\n  // Find previous previous character pointer. (2)\n  gchar *first_char_ptr = g_utf8_find_prev_char(tb->text, second_char_ptr);\n  if (first_char_ptr == NULL) {\n    // Failed to move cursor back 2 characters, so we cannot swap.\n    return;\n  }\n  // Calculate size of each character\n  size_t first_char_l = second_char_ptr - first_char_ptr;\n  size_t second_char_l = cursor_ptr - second_char_ptr;\n  // Create a temp buffer so we can swap.\n  gchar temp[second_char_l+ first_char_l];\n  // Copy char 2 into first place.\n  memcpy(temp, second_char_ptr, second_char_l);\n  // Copy char 1 into 2nd place.\n  memcpy(temp + second_char_l, first_char_ptr, first_char_l);\n  // Copy new order back into original string.\n  memcpy(first_char_ptr, temp, second_char_l+ first_char_l);\n  // Set modified, lay out need te be redrawn\n  // Stop blink!\n  tb->blink = 2;\n  tb->changed = TRUE;\n}\nstatic void textbox_cursor_bkspc_word(textbox *tb) {\n  if (tb && tb->cursor > 0) {\n    int cursor = tb->cursor;\n    textbox_cursor_dec_word(tb);\n    if (cursor > tb->cursor) {\n      textbox_delete(tb, tb->cursor, cursor - tb->cursor);\n    }\n  }\n}\nstatic void textbox_cursor_del_eol(textbox *tb) {\n  if (tb && tb->cursor >= 0) {\n    int length = g_utf8_strlen(tb->text, -1) - tb->cursor;\n    if (length >= 0) {\n      textbox_delete(tb, tb->cursor, length);\n    }\n  }\n}\nstatic void textbox_cursor_del_sol(textbox *tb) {\n  if (tb && tb->cursor >= 0) {\n    int length = tb->cursor;\n    textbox_delete(tb, 0, length);\n  }\n}\nstatic void textbox_cursor_del_word(textbox *tb) {\n  if (tb && tb->cursor >= 0) {\n    int cursor = tb->cursor;\n    textbox_cursor_inc_word(tb);\n    if (cursor < tb->cursor) {\n      textbox_delete(tb, cursor, tb->cursor - cursor);\n    }\n  }\n}\n\n// handle a keypress in edit mode\n// 2 = nav\n// 0 = unhandled\n// 1 = handled\n// -1 = handled and return pressed (finished)\nint textbox_keybinding(textbox *tb, KeyBindingAction action) {\n  if (tb == NULL) {\n    return 0;\n  }\n  if (!(tb->flags & TB_EDITABLE)) {\n    return 0;\n  }\n\n  switch (action) {\n  // Left or Ctrl-b\n  case MOVE_CHAR_BACK:\n    return (textbox_cursor_dec(tb) == TRUE) ? 2 : 0;\n  // Right or Ctrl-F\n  case MOVE_CHAR_FORWARD:\n    return (textbox_cursor_inc(tb) == TRUE) ? 2 : 0;\n  // Ctrl-U: Kill from the beginning to the end of the line.\n  case CLEAR_LINE:\n    textbox_text(tb, \"\");\n    return 1;\n  // Ctrl-A\n  case MOVE_FRONT:\n    textbox_cursor(tb, 0);\n    return 2;\n  // Ctrl-E\n  case MOVE_END:\n    textbox_cursor_end(tb);\n    return 2;\n  // Ctrl-Alt-h\n  case REMOVE_WORD_BACK:\n    textbox_cursor_bkspc_word(tb);\n    return 1;\n  // Ctrl-Alt-d\n  case REMOVE_WORD_FORWARD:\n    textbox_cursor_del_word(tb);\n    return 1;\n  case REMOVE_TO_EOL:\n    textbox_cursor_del_eol(tb);\n    return 1;\n  case REMOVE_TO_SOL:\n    textbox_cursor_del_sol(tb);\n    return 1;\n  // Delete or Ctrl-D\n  case REMOVE_CHAR_FORWARD:\n    textbox_cursor_del(tb);\n    return 1;\n  // Alt-B, Ctrl-Left\n  case MOVE_WORD_BACK:\n    textbox_cursor_dec_word(tb);\n    return 2;\n  // Alt-F, Ctrl-Right\n  case MOVE_WORD_FORWARD:\n    textbox_cursor_inc_word(tb);\n    return 2;\n  // BackSpace, Shift-BackSpace, Ctrl-h\n  case REMOVE_CHAR_BACK:\n    textbox_cursor_bkspc(tb);\n    return 1;\n  case TRANSPOSE_CHARS:\n    textbox_transpose_chars(tb);\n    return 1;\n  default:\n    g_return_val_if_reached(0);\n  }\n}\n\ngboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len) {\n  if (tb == NULL) {\n    return FALSE;\n  }\n  if (!(tb->flags & TB_EDITABLE)) {\n    return FALSE;\n  }\n\n  // Filter When alt/ctrl is pressed do not accept the character.\n\n  gboolean used_something = FALSE;\n  const gchar *w, *n, *e;\n  for (w = pad, n = g_utf8_next_char(w), e = w + pad_len; w < e;\n       w = n, n = g_utf8_next_char(n)) {\n    gunichar c = g_utf8_get_char(w);\n    if (g_unichar_isspace(c)) {\n      /** Replace tabs, newlines and others with a normal space. */\n      textbox_insert(tb, tb->cursor, \" \", 1);\n      textbox_cursor(tb, tb->cursor + 1);\n      used_something = TRUE;\n    } else if (g_unichar_iscntrl(c)) {\n      /* skip control characters. */\n      g_info(\"Got an invalid character: %08X\", c);\n    } else {\n      /** Insert the text */\n      textbox_insert(tb, tb->cursor, w, n - w);\n      textbox_cursor(tb, tb->cursor + 1);\n      used_something = TRUE;\n    }\n  }\n  return used_something;\n}\n\nstatic void tbfc_entry_free(TBFontConfig *tbfc) {\n  pango_font_metrics_unref(tbfc->metrics);\n  if (tbfc->pfd) {\n    pango_font_description_free(tbfc->pfd);\n  }\n  g_free(tbfc);\n}\nvoid textbox_setup(void) {\n  tbfc_cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,\n                                     (GDestroyNotify)tbfc_entry_free);\n}\n\n/** Name of the default font (if none is given) */\nconst char *default_font_name = \"default\";\nvoid textbox_set_pango_context(const char *font, PangoContext *p) {\n  g_assert(p_metrics == NULL);\n  p_context = g_object_ref(p);\n  p_metrics = pango_context_get_metrics(p_context, NULL, NULL);\n  TBFontConfig *tbfc = g_malloc0(sizeof(TBFontConfig));\n  tbfc->metrics = p_metrics;\n\n  PangoLayout *layout = pango_layout_new(p_context);\n  pango_layout_set_text(layout, \"aAjb\", -1);\n  PangoRectangle rect;\n  pango_layout_get_pixel_extents(layout, NULL, &rect);\n  tbfc->height = rect.y + rect.height;\n  if (tbfc->metrics) {\n    int h = pango_font_metrics_get_height(tbfc->metrics) / PANGO_SCALE;\n    if (h > 0) {\n      tbfc->height = h;\n    }\n  }\n  g_object_unref(layout);\n  tbfc_default = tbfc;\n\n  g_hash_table_insert(tbfc_cache, (gpointer *)(font ? font : default_font_name),\n                      tbfc);\n}\n\nvoid textbox_cleanup(void) {\n  g_hash_table_destroy(tbfc_cache);\n  if (p_context) {\n    g_object_unref(p_context);\n    p_context = NULL;\n  }\n}\n\nint textbox_get_width(widget *wid) {\n  textbox *tb = (textbox *)wid;\n  if (tb->flags & TB_AUTOWIDTH) {\n    return textbox_get_font_width(tb) + widget_padding_get_padding_width(wid);\n  }\n  return tb->widget.w;\n}\n\nint _textbox_get_height(widget *wid) {\n  textbox *tb = (textbox *)wid;\n  if (tb->flags & TB_AUTOHEIGHT) {\n    return textbox_get_estimated_height(\n        tb, pango_layout_get_line_count(tb->layout));\n  }\n  return tb->widget.h;\n}\nint textbox_get_height(const textbox *tb) {\n  return textbox_get_font_height(tb) +\n         widget_padding_get_padding_height(WIDGET(tb));\n}\n\nint textbox_get_font_height(const textbox *tb) {\n  PangoRectangle rect;\n  pango_layout_get_pixel_extents(tb->layout, NULL, &rect);\n  return rect.height + rect.y;\n}\n\nint textbox_get_font_width(const textbox *tb) {\n  PangoRectangle rect;\n  pango_layout_get_pixel_extents(tb->layout, NULL, &rect);\n  return rect.width + rect.x;\n}\n\n/** Caching for the estimated character height. (em) */\ndouble textbox_get_estimated_char_height(void) { return tbfc_default->height; }\n\n/** Caching for the expected character width. */\nstatic double char_width = -1;\ndouble textbox_get_estimated_char_width(void) {\n  if (char_width < 0) {\n    int width = pango_font_metrics_get_approximate_char_width(p_metrics);\n    char_width = (width) / (double)PANGO_SCALE;\n  }\n  return char_width;\n}\n\n/** Cache storing the estimated width of a digit (ch). */\nstatic double ch_width = -1;\ndouble textbox_get_estimated_ch(void) {\n  if (ch_width < 0) {\n    int width = pango_font_metrics_get_approximate_digit_width(p_metrics);\n    ch_width = (width) / (double)PANGO_SCALE;\n  }\n  return ch_width;\n}\n\nint textbox_get_estimated_height(const textbox *tb, int eh) {\n  int height = tb->tbfc->height;\n  return (eh * height) + widget_padding_get_padding_height(WIDGET(tb));\n}\nint textbox_get_desired_width(widget *wid, G_GNUC_UNUSED const int height) {\n  if (wid == NULL) {\n    return 0;\n  }\n  textbox *tb = (textbox *)wid;\n  if (wid->expand && tb->flags & TB_AUTOWIDTH) {\n    return textbox_get_font_width(tb) + widget_padding_get_padding_width(wid);\n  }\n  RofiDistance w = rofi_theme_get_distance(WIDGET(tb), \"width\", 0);\n  int wi = distance_get_pixel(w, ROFI_ORIENTATION_HORIZONTAL);\n  if (wi > 0) {\n    return wi;\n  }\n  int padding = widget_padding_get_left(WIDGET(tb));\n  padding += widget_padding_get_right(WIDGET(tb));\n  int old_width = pango_layout_get_width(tb->layout);\n  pango_layout_set_width(tb->layout, -1);\n  int width = textbox_get_font_width(tb);\n  // Restore.\n  pango_layout_set_width(tb->layout, old_width);\n  return width + padding;\n}\n\nvoid textbox_set_ellipsize(textbox *tb, PangoEllipsizeMode mode) {\n  if (tb) {\n    tb->emode = mode;\n    if ((tb->flags & TB_WRAP) != TB_WRAP) {\n      // Store the mode.\n      pango_layout_set_ellipsize(tb->layout, tb->emode);\n      widget_queue_redraw(WIDGET(tb));\n    }\n  }\n}\nint textbox_get_cursor_x_pos(const textbox *tb) {\n  if (tb == NULL) {\n    return 0;\n  }\n  return tb->cursor_x_pos;\n}\n"
  },
  {
    "path": "source/widgets/widget.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"cairo.h\"\n#include \"config.h\"\n\n#include \"theme.h\"\n#include \"widgets/widget-internal.h\"\n#include \"widgets/widget.h\"\n#include <glib.h>\n#include <math.h>\n\nvoid widget_init(widget *wid, widget *parent, WidgetType type,\n                 const char *name) {\n  wid->type = type;\n  wid->parent = parent;\n  wid->name = g_strdup(name);\n  wid->def_padding = WIDGET_PADDING_INIT;\n  wid->def_border = WIDGET_PADDING_INIT;\n  wid->def_border_radius = WIDGET_PADDING_INIT;\n  wid->def_margin = WIDGET_PADDING_INIT;\n\n  wid->padding = rofi_theme_get_padding(wid, \"padding\", wid->def_padding);\n  wid->border = rofi_theme_get_padding(wid, \"border\", wid->def_border);\n  wid->border_radius =\n      rofi_theme_get_padding(wid, \"border-radius\", wid->def_border_radius);\n  wid->margin = rofi_theme_get_padding(wid, \"margin\", wid->def_margin);\n\n  wid->cursor_type =\n      rofi_theme_get_cursor_type(wid, \"cursor\", ROFI_CURSOR_DEFAULT);\n\n  // enabled by default\n  wid->enabled = rofi_theme_get_boolean(wid, \"enabled\", TRUE);\n\n  wid->border_antialiasing = rofi_theme_get_boolean(wid, \"border-aa\", TRUE);\n  wid->border_disable_nvidia_workaround =\n      rofi_theme_get_boolean(wid, \"border-disable-nvidia-workaround\", FALSE);\n}\n\nvoid widget_set_state(widget *wid, const char *state) {\n  if (wid == NULL) {\n    return;\n  }\n  if (g_strcmp0(wid->state, state)) {\n    wid->state = state;\n    // Update border.\n    wid->border = rofi_theme_get_padding(wid, \"border\", wid->def_border);\n    wid->border_radius =\n        rofi_theme_get_padding(wid, \"border-radius\", wid->def_border_radius);\n    if (wid->set_state != NULL) {\n      wid->set_state(wid, state);\n    }\n    widget_queue_redraw(wid);\n  }\n}\n\nint widget_intersect(const widget *wid, int x, int y) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n\n  if (x >= (wid->x) && x < (wid->x + wid->w) && y >= (wid->y) &&\n      y < (wid->y + wid->h)) {\n    return TRUE;\n  }\n  return FALSE;\n}\n\nvoid widget_resize(widget *wid, short w, short h) {\n  if (wid == NULL) {\n    return;\n  }\n  if (wid->resize != NULL) {\n    if (wid->w != w || wid->h != h) {\n      wid->resize(wid, w, h);\n    }\n  } else {\n    wid->w = w;\n    wid->h = h;\n  }\n  // On a resize we always want to update.\n  widget_queue_redraw(wid);\n}\nvoid widget_move(widget *wid, short x, short y) {\n  if (wid == NULL) {\n    return;\n  }\n  wid->x = x;\n  wid->y = y;\n}\nvoid widget_set_type(widget *wid, WidgetType type) {\n  if (wid == NULL) {\n    return;\n  }\n  wid->type = type;\n}\n\ngboolean widget_enabled(widget *wid) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n  return wid->enabled;\n}\n\nvoid widget_set_enabled(widget *wid, gboolean enabled) {\n  if (wid == NULL) {\n    return;\n  }\n  if (wid->enabled != enabled) {\n    wid->enabled = enabled;\n    widget_update(wid);\n    widget_update(wid->parent);\n    widget_queue_redraw(wid);\n  }\n}\n\nvoid widget_draw(widget *wid, cairo_t *d) {\n  if (wid == NULL) {\n    return;\n  }\n  // Check if enabled and if draw is implemented.\n  if (wid->enabled && wid->draw) {\n    // Don't draw if there is no space.\n    if (wid->h < 1 || wid->w < 1) {\n      wid->need_redraw = FALSE;\n      return;\n    }\n    // Store current state.\n    cairo_save(d);\n    const int margin_left =\n        distance_get_pixel(wid->margin.left, ROFI_ORIENTATION_HORIZONTAL);\n    const int margin_top =\n        distance_get_pixel(wid->margin.top, ROFI_ORIENTATION_VERTICAL);\n    const int margin_right =\n        distance_get_pixel(wid->margin.right, ROFI_ORIENTATION_HORIZONTAL);\n    const int margin_bottom =\n        distance_get_pixel(wid->margin.bottom, ROFI_ORIENTATION_VERTICAL);\n    const int left =\n        distance_get_pixel(wid->border.left, ROFI_ORIENTATION_HORIZONTAL);\n    const int right =\n        distance_get_pixel(wid->border.right, ROFI_ORIENTATION_HORIZONTAL);\n    const int top =\n        distance_get_pixel(wid->border.top, ROFI_ORIENTATION_VERTICAL);\n    const int bottom =\n        distance_get_pixel(wid->border.bottom, ROFI_ORIENTATION_VERTICAL);\n    int radius_bl = distance_get_pixel(wid->border_radius.left,\n                                       ROFI_ORIENTATION_HORIZONTAL);\n    int radius_tr = distance_get_pixel(wid->border_radius.right,\n                                       ROFI_ORIENTATION_HORIZONTAL);\n    int radius_tl =\n        distance_get_pixel(wid->border_radius.top, ROFI_ORIENTATION_VERTICAL);\n    int radius_br = distance_get_pixel(wid->border_radius.bottom,\n                                       ROFI_ORIENTATION_VERTICAL);\n\n    double vspace =\n        wid->h - margin_top - margin_bottom - top / 2.0 - bottom / 2.0;\n    double hspace =\n        wid->w - margin_left - margin_right - left / 2.0 - right / 2.0;\n    if ((radius_bl + radius_tl) > (vspace)) {\n      int j = ((vspace) / 2.0);\n      radius_bl = MIN(radius_bl, j);\n      radius_tl = MIN(radius_tl, j);\n    }\n    if ((radius_br + radius_tr) > (vspace)) {\n      int j = ((vspace) / 2.0);\n      radius_br = MIN(radius_br, j);\n      radius_tr = MIN(radius_tr, j);\n    }\n    if ((radius_tl + radius_tr) > (hspace)) {\n      int j = ((hspace) / 2.0);\n      radius_tr = MIN(radius_tr, j);\n      radius_tl = MIN(radius_tl, j);\n    }\n    if ((radius_bl + radius_br) > (hspace)) {\n      int j = ((hspace) / 2.0);\n      radius_br = MIN(radius_br, j);\n      radius_bl = MIN(radius_bl, j);\n    }\n\n    // Background painting.\n    // Set new x/y position.\n    cairo_translate(d, wid->x, wid->y);\n    cairo_set_line_width(d, 0);\n\n    // Outer outline outlines\n    double x1, y1, x2, y2;\n    x1 = margin_left + left / 2.0, y1 = margin_top + top / 2.0,\n    x2 = wid->w - margin_right - right / 2.0,\n    y2 = wid->h - margin_bottom - bottom / 2.0;\n\n    if (radius_tl > 0) {\n      cairo_move_to(d, x1, y1 + radius_tl);\n      cairo_arc(d, x1 + radius_tl, y1 + radius_tl, radius_tl, -1.0 * G_PI,\n                -G_PI_2);\n    } else {\n      cairo_move_to(d, x1, y1);\n    }\n    if (radius_tr > 0) {\n      cairo_line_to(d, x2 - radius_tr, y1);\n      cairo_arc(d, x2 - radius_tr, y1 + radius_tr, radius_tr, -G_PI_2,\n                0 * G_PI);\n    } else {\n      cairo_line_to(d, x2, y1);\n    }\n    if (radius_br > 0) {\n      cairo_line_to(d, x2, y2 - radius_br);\n      cairo_arc(d, x2 - radius_br, y2 - radius_br, radius_br, 0.0 * G_PI,\n                G_PI_2);\n    } else {\n      cairo_line_to(d, x2, y2);\n    }\n    if (radius_bl > 0) {\n      cairo_line_to(d, x1 + radius_bl, y2);\n      cairo_arc(d, x1 + radius_bl, y2 - radius_bl, radius_bl, G_PI_2,\n                1.0 * G_PI);\n    } else {\n      cairo_line_to(d, x1, y2);\n    }\n    cairo_close_path(d);\n\n    cairo_set_source_rgba(d, 1.0, 1.0, 1.0, 1.0);\n    rofi_theme_get_color(wid, \"background-color\", d);\n    cairo_fill_preserve(d);\n    if (rofi_theme_get_image(wid, \"background-image\", d)) {\n      cairo_fill_preserve(d);\n    }\n    cairo_clip(d);\n\n    wid->draw(wid, d);\n    wid->need_redraw = FALSE;\n\n    cairo_restore(d);\n\n    if (left != 0 || top != 0 || right != 0 || bottom != 0) {\n      cairo_save(d);\n      if (wid->border_antialiasing == FALSE) {\n        cairo_set_antialias(d, CAIRO_ANTIALIAS_NONE);\n      }\n      if (wid->border_disable_nvidia_workaround) {\n        cairo_set_operator(d, CAIRO_OPERATOR_ADD);\n      }\n      cairo_translate(d, wid->x, wid->y);\n      cairo_new_path(d);\n      rofi_theme_get_color(wid, \"border-color\", d);\n\n      // Calculate the different offsets for the corners.\n      double minof_tr = MIN(right / 2.0, top / 2.0);\n      double minof_tl = MIN(left / 2.0, top / 2.0);\n      double minof_br = MIN(right / 2.0, bottom / 2.0);\n      double minof_bl = MIN(left / 2.0, bottom / 2.0);\n      // Inner radius\n      double radius_inner_tl = radius_tl - minof_tl;\n      double radius_inner_tr = radius_tr - minof_tr;\n      double radius_inner_bl = radius_bl - minof_bl;\n      double radius_inner_br = radius_br - minof_br;\n\n      // Offsets of the different lines in each corner.\n      //\n      //      |             |\n      //     ttl           ttr\n      //      |             |\n      // -ltl-###############-rtr-\n      //      $             $\n      //      $             $\n      // -lbl-###############-rbr-\n      //      |             |\n      //     bbl           bbr\n      //      |             |\n      //\n      // The left and right part ($) start at thinkness top bottom when no\n      // radius\n      double offset_ltl =\n          (radius_inner_tl > 0) ? (left) + radius_inner_tl : left;\n      double offset_rtr =\n          (radius_inner_tr > 0) ? (right) + radius_inner_tr : right;\n      double offset_lbl =\n          (radius_inner_bl > 0) ? (left) + radius_inner_bl : left;\n      double offset_rbr =\n          (radius_inner_br > 0) ? (right) + radius_inner_br : right;\n      // The top and bottom part (#) go into the corner when no radius\n      double offset_ttl = (radius_inner_tl > 0) ? (top) + radius_inner_tl\n                          : (radius_tl > 0)     ? top\n                                                : 0;\n      double offset_ttr = (radius_inner_tr > 0) ? (top) + radius_inner_tr\n                          : (radius_tr > 0)     ? top\n                                                : 0;\n      double offset_bbl = (radius_inner_bl > 0) ? (bottom) + radius_inner_bl\n                          : (radius_bl > 0)     ? bottom\n                                                : 0;\n      double offset_bbr = (radius_inner_br > 0) ? (bottom) + radius_inner_br\n                          : (radius_br > 0)     ? bottom\n                                                : 0;\n\n      if (left > 0) {\n        cairo_set_line_width(d, left);\n        distance_get_linestyle(wid->border.left, d);\n        cairo_move_to(d, x1, margin_top + offset_ttl);\n        cairo_line_to(d, x1, wid->h - margin_bottom - offset_bbl);\n        cairo_stroke(d);\n      }\n      if (right > 0) {\n        cairo_set_line_width(d, right);\n        distance_get_linestyle(wid->border.right, d);\n        cairo_move_to(d, x2, margin_top + offset_ttr);\n        cairo_line_to(d, x2, wid->h - margin_bottom - offset_bbr);\n        cairo_stroke(d);\n      }\n      if (top > 0) {\n        cairo_set_line_width(d, top);\n        distance_get_linestyle(wid->border.top, d);\n        cairo_move_to(d, margin_left + offset_ltl, y1);\n        cairo_line_to(d, wid->w - margin_right - offset_rtr, y1);\n        cairo_stroke(d);\n      }\n      if (bottom > 0) {\n        cairo_set_line_width(d, bottom);\n        distance_get_linestyle(wid->border.bottom, d);\n        cairo_move_to(d, margin_left + offset_lbl, y2);\n        cairo_line_to(d, wid->w - margin_right - offset_rbr, y2);\n        cairo_stroke(d);\n      }\n      if (radius_tl > 0) {\n        double radius_outer = radius_tl + minof_tl;\n        cairo_arc(d, margin_left + radius_outer, margin_top + radius_outer,\n                  radius_outer, -G_PI, -G_PI_2);\n        cairo_line_to(d, margin_left + offset_ltl, margin_top);\n        cairo_line_to(d, margin_left + offset_ltl, margin_top + top);\n        if (radius_inner_tl > 0) {\n          cairo_arc_negative(d, margin_left + left + radius_inner_tl,\n                             margin_top + top + radius_inner_tl,\n                             radius_inner_tl, -G_PI_2, G_PI);\n          cairo_line_to(d, margin_left + left, margin_top + offset_ttl);\n        }\n        cairo_line_to(d, margin_left, margin_top + offset_ttl);\n        cairo_close_path(d);\n        cairo_fill(d);\n      }\n      if (radius_tr > 0) {\n        double radius_outer = radius_tr + minof_tr;\n        cairo_arc(d, wid->w - margin_right - radius_outer,\n                  margin_top + radius_outer, radius_outer, -G_PI_2, 0);\n        cairo_line_to(d, wid->w - margin_right, margin_top + offset_ttr);\n        cairo_line_to(d, wid->w - margin_right - right,\n                      margin_top + offset_ttr);\n        if (radius_inner_tr > 0) {\n          cairo_arc_negative(d, wid->w - margin_right - right - radius_inner_tr,\n                             margin_top + top + radius_inner_tr,\n                             radius_inner_tr, 0, -G_PI_2);\n          cairo_line_to(d, wid->w - margin_right - offset_rtr,\n                        margin_top + top);\n        }\n        cairo_line_to(d, wid->w - margin_right - offset_rtr, margin_top);\n        cairo_close_path(d);\n        cairo_fill(d);\n      }\n      if (radius_br > 0) {\n        double radius_outer = radius_br + minof_br;\n        cairo_arc(d, wid->w - margin_right - radius_outer,\n                  wid->h - margin_bottom - radius_outer, radius_outer, 0.0,\n                  G_PI_2);\n        cairo_line_to(d, wid->w - margin_right - offset_rbr,\n                      wid->h - margin_bottom);\n        cairo_line_to(d, wid->w - margin_right - offset_rbr,\n                      wid->h - margin_bottom - bottom);\n        if (radius_inner_br > 0) {\n          cairo_arc_negative(d, wid->w - margin_right - right - radius_inner_br,\n                             wid->h - margin_bottom - bottom - radius_inner_br,\n                             radius_inner_br, G_PI_2, 0.0);\n          cairo_line_to(d, wid->w - margin_right - right,\n                        wid->h - margin_bottom - offset_bbr);\n        }\n        cairo_line_to(d, wid->w - margin_right,\n                      wid->h - margin_bottom - offset_bbr);\n        cairo_close_path(d);\n        cairo_fill(d);\n      }\n      if (radius_bl > 0) {\n        double radius_outer = radius_bl + minof_bl;\n        cairo_arc(d, margin_left + radius_outer,\n                  wid->h - margin_bottom - radius_outer, radius_outer, G_PI_2,\n                  G_PI);\n        cairo_line_to(d, margin_left, wid->h - margin_bottom - offset_bbl);\n        cairo_line_to(d, margin_left + left,\n                      wid->h - margin_bottom - offset_bbl);\n        if (radius_inner_bl > 0) {\n          cairo_arc_negative(d, margin_left + left + radius_inner_bl,\n                             wid->h - margin_bottom - bottom - radius_inner_bl,\n                             radius_inner_bl, G_PI, G_PI_2);\n          cairo_line_to(d, margin_left + offset_lbl,\n                        wid->h - margin_bottom - bottom);\n        }\n        cairo_line_to(d, margin_left + offset_lbl, wid->h - margin_bottom);\n        cairo_close_path(d);\n\n        cairo_fill(d);\n      }\n      cairo_restore(d);\n    }\n  }\n}\n\nvoid widget_free(widget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n  if (wid->name != NULL) {\n    g_free(wid->name);\n  }\n  if (wid->free != NULL) {\n    wid->free(wid);\n  }\n}\n\nint widget_get_height(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  if (wid->get_height == NULL) {\n    return wid->h;\n  }\n  return wid->get_height(wid);\n}\nint widget_get_width(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  if (wid->get_width == NULL) {\n    return wid->w;\n  }\n  return wid->get_width(wid);\n}\nint widget_get_x_pos(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  return wid->x;\n}\nint widget_get_y_pos(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  return wid->y;\n}\n\nvoid widget_xy_to_relative(widget *wid, gint *x, gint *y) {\n  *x -= wid->x;\n  *y -= wid->y;\n  if (wid->parent == NULL) {\n    return;\n  }\n  widget_xy_to_relative(wid->parent, x, y);\n}\n\nvoid widget_update(widget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n  // When (desired )size of wid changes.\n  if (wid->update != NULL) {\n    wid->update(wid);\n  }\n}\n\nvoid widget_queue_redraw(widget *wid) {\n  if (wid == NULL) {\n    return;\n  }\n  widget *iter = wid;\n  // Find toplevel widget.\n  while (iter->parent != NULL) {\n    iter->need_redraw = TRUE;\n    iter = iter->parent;\n  }\n  iter->need_redraw = TRUE;\n}\n\ngboolean widget_need_redraw(widget *wid) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n  if (!wid->enabled) {\n    return FALSE;\n  }\n  return wid->need_redraw;\n}\n\nwidget *widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y) {\n  if (wid == NULL) {\n    return NULL;\n  }\n\n  if (wid->find_mouse_target != NULL) {\n    widget *target = wid->find_mouse_target(wid, type, x, y);\n    if (target != NULL) {\n      return target;\n    }\n  }\n\n  if (wid->type == type || type == WIDGET_TYPE_UNKNOWN) {\n    return wid;\n  }\n\n  return NULL;\n}\n\nWidgetTriggerActionResult widget_check_action(widget *wid,\n                                              G_GNUC_UNUSED guint action,\n                                              G_GNUC_UNUSED gint x,\n                                              G_GNUC_UNUSED gint y) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n  if (wid->trigger_action == NULL) {\n    return FALSE;\n  }\n  /*\n   * TODO: We should probably add a check_action callback to the widgets\n   * to do extra checks\n   */\n  return WIDGET_TRIGGER_ACTION_RESULT_HANDLED;\n}\n\nWidgetTriggerActionResult widget_trigger_action(widget *wid, guint action,\n                                                gint x, gint y) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n  if (wid->trigger_action == NULL) {\n    return FALSE;\n  }\n  return wid->trigger_action(wid, action, x, y, wid->trigger_action_cb_data);\n}\n\nvoid widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb,\n                                       void *cb_data) {\n  if (wid == NULL) {\n    return;\n  }\n  wid->trigger_action = cb;\n  wid->trigger_action_cb_data = cb_data;\n}\n\ngboolean widget_motion_notify(widget *wid, gint x, gint y) {\n  if (wid == NULL) {\n    return FALSE;\n  }\n  if (wid->motion_notify == NULL) {\n    return FALSE;\n  }\n  return wid->motion_notify(wid, x, y);\n}\n\nint widget_padding_get_left(const widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int distance =\n      distance_get_pixel(wid->padding.left, ROFI_ORIENTATION_HORIZONTAL);\n  distance += distance_get_pixel(wid->border.left, ROFI_ORIENTATION_HORIZONTAL);\n  distance += distance_get_pixel(wid->margin.left, ROFI_ORIENTATION_HORIZONTAL);\n  return distance;\n}\nint widget_padding_get_right(const widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int distance =\n      distance_get_pixel(wid->padding.right, ROFI_ORIENTATION_HORIZONTAL);\n  distance +=\n      distance_get_pixel(wid->border.right, ROFI_ORIENTATION_HORIZONTAL);\n  distance +=\n      distance_get_pixel(wid->margin.right, ROFI_ORIENTATION_HORIZONTAL);\n  return distance;\n}\nint widget_padding_get_top(const widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int distance =\n      distance_get_pixel(wid->padding.top, ROFI_ORIENTATION_VERTICAL);\n  distance += distance_get_pixel(wid->border.top, ROFI_ORIENTATION_VERTICAL);\n  distance += distance_get_pixel(wid->margin.top, ROFI_ORIENTATION_VERTICAL);\n  return distance;\n}\nint widget_padding_get_bottom(const widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int distance =\n      distance_get_pixel(wid->padding.bottom, ROFI_ORIENTATION_VERTICAL);\n  distance += distance_get_pixel(wid->border.bottom, ROFI_ORIENTATION_VERTICAL);\n  distance += distance_get_pixel(wid->margin.bottom, ROFI_ORIENTATION_VERTICAL);\n  return distance;\n}\n\nint widget_padding_get_remaining_width(const widget *wid) {\n  int width = wid->w;\n  width -= widget_padding_get_left(wid);\n  width -= widget_padding_get_right(wid);\n  return width;\n}\nint widget_padding_get_remaining_height(const widget *wid) {\n  int height = wid->h;\n  height -= widget_padding_get_top(wid);\n  height -= widget_padding_get_bottom(wid);\n  return height;\n}\nint widget_padding_get_padding_height(const widget *wid) {\n  int height = 0;\n  height += widget_padding_get_top(wid);\n  height += widget_padding_get_bottom(wid);\n  return height;\n}\nint widget_padding_get_padding_width(const widget *wid) {\n  int width = 0;\n  width += widget_padding_get_left(wid);\n  width += widget_padding_get_right(wid);\n  return width;\n}\n\nint widget_get_desired_height(widget *wid, const int width) {\n  if (wid == NULL) {\n    return 0;\n  }\n  if (wid->get_desired_height == NULL) {\n    return wid->h;\n  }\n  return wid->get_desired_height(wid, width);\n}\nint widget_get_desired_width(widget *wid, const int height) {\n  if (wid == NULL) {\n    return 0;\n  }\n  if (wid->get_desired_width == NULL) {\n    return wid->w;\n  }\n  return wid->get_desired_width(wid, height);\n}\n\nint widget_get_absolute_xpos(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int retv = wid->x;\n  if (wid->parent != NULL) {\n    retv += widget_get_absolute_xpos(wid->parent);\n  }\n  return retv;\n}\nint widget_get_absolute_ypos(widget *wid) {\n  if (wid == NULL) {\n    return 0;\n  }\n  int retv = wid->y;\n  if (wid->parent != NULL) {\n    retv += widget_get_absolute_ypos(wid->parent);\n  }\n  return retv;\n}\n"
  },
  {
    "path": "source/xcb/display.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** Log domain for this module */\n#define G_LOG_DOMAIN \"X11Helper\"\n\n#include <config.h>\n\n#ifdef XCB_IMDKIT\n#include <xcb-imdkit/encoding.h>\n#include <xcb/xcb_keysyms.h>\n#endif\n#include <cairo-xcb.h>\n#include <cairo.h>\n#include <glib.h>\n#include <math.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <xcb/randr.h>\n#include <xcb/xcb.h>\n#include <xcb/xcb_aux.h>\n#include <xcb/xcb_cursor.h>\n#include <xcb/xcb_ewmh.h>\n#include <xcb/xinerama.h>\n#include <xcb/xkb.h>\n#include <xcb/xproto.h>\n#include <xkbcommon/xkbcommon-x11.h>\n#include <xkbcommon/xkbcommon.h>\n/** Indicate that we know the startup notification api is not yet stable. */\n#define SN_API_NOT_YET_FROZEN\n/** This function is declared as sn_launcher_context_set_application_id but\n * implemented as sn_launcher_set_application_id. Quick Fix. */\n#define sn_launcher_context_set_application_id sn_launcher_set_application_id\n#include \"display-internal.h\"\n#include \"display.h\"\n#include \"helper.h\"\n#include \"rofi-types.h\"\n#include \"settings.h\"\n#include \"timings.h\"\n#include \"xcb-internal.h\"\n#include \"xcb.h\"\n#include <libsn/sn.h>\n#include <stdbool.h>\n\n#include \"mode.h\"\n#include \"modes/window.h\"\n\n#include <rofi.h>\n\n/** Minimal randr preferred for running rofi (1.5) (Major version number) */\n#define RANDR_PREF_MAJOR_VERSION 1\n/** Minimal randr preferred for running rofi (1.5) (Minor version number) */\n#define RANDR_PREF_MINOR_VERSION 5\n\n/** Checks if the if x and y is inside rectangle. */\n#define INTERSECT(x, y, x1, y1, w1, h1)                                        \\\n  ((((x) >= (x1)) && ((x) < (x1 + w1))) && (((y) >= (y1)) && ((y) < (y1 + h1))))\n\nWindowManagerQuirk current_window_manager = WM_EWHM;\n\n/**\n * Structure holding xcb objects needed to function.\n */\nstruct _xcb_stuff xcb_int = {.connection = NULL,\n                             .screen = NULL,\n#ifdef XCB_IMDKIT\n                             .im = NULL,\n                             .syms = NULL,\n#endif\n                             .screen_nbr = -1,\n                             .sndisplay = NULL,\n                             .sncontext = NULL,\n                             .monitors = NULL,\n                             .clipboard = NULL};\nxcb_stuff *xcb = &xcb_int;\n\n/**\n * Depth of root window.\n */\nxcb_depth_t *depth = NULL;\nxcb_visualtype_t *visual = NULL;\nxcb_colormap_t map = XCB_COLORMAP_NONE;\n/**\n * Visual of the root window.\n */\nstatic xcb_visualtype_t *root_visual = NULL;\nxcb_atom_t netatoms[NUM_NETATOMS];\nconst char *netatom_names[] = {EWMH_ATOMS(ATOM_CHAR)};\n\n/**\n * Cached X11 cursors.\n */\nxcb_cursor_t cursors[NUM_CURSORS] = {XCB_CURSOR_NONE, XCB_CURSOR_NONE,\n                                     XCB_CURSOR_NONE};\n\n/** Mapping between theme name and system name for mouse cursor. */\nconst struct {\n  /** Theme name */\n  const char *css_name;\n  /** System name */\n  const char *traditional_name;\n} cursor_names[] = {\n    {\"default\", \"left_ptr\"}, {\"pointer\", \"hand\"}, {\"text\", \"xterm\"}};\n\nstatic xcb_visualtype_t *lookup_visual(xcb_screen_t *s, xcb_visualid_t vis) {\n  xcb_depth_iterator_t d;\n  d = xcb_screen_allowed_depths_iterator(s);\n  for (; d.rem; xcb_depth_next(&d)) {\n    xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);\n    for (; v.rem; xcb_visualtype_next(&v)) {\n      if (v.data->visual_id == vis) {\n        return v.data;\n      }\n    }\n  }\n  return 0;\n}\n\n/* This blur function was originally created my MacSlow and published on his\n * website: http://macslow.thepimp.net. I'm not entirely sure he's proud of it,\n * but it has proved immeasurably useful for me. */\n\nstatic uint32_t *create_kernel(int radius, double deviation, uint32_t *sum2) {\n  int size = 2 * (radius) + 1;\n  uint32_t *kernel = (uint32_t *)(g_malloc(sizeof(uint32_t) * (size + 1)));\n  double radiusf = abs(radius) + 1.0;\n  double value = -radius;\n  double sum = 0.0;\n  int i;\n\n  if (deviation == 0.0) {\n    deviation = sqrt(-(radiusf * radiusf) / (2.0 * log(1.0 / 255.0)));\n  }\n\n  kernel[0] = size;\n\n  for (i = 0; i < size; i++) {\n    kernel[1 + i] = INT16_MAX / (2.506628275 * deviation) *\n                    exp(-((value * value) / (2.0 * (deviation * deviation))));\n\n    sum += kernel[1 + i];\n    value += 1.0;\n  }\n\n  *sum2 = sum;\n\n  return kernel;\n}\n\nvoid cairo_image_surface_blur(cairo_surface_t *surface, int radius,\n                              double deviation) {\n  uint32_t *horzBlur;\n  uint32_t *kernel = 0;\n  cairo_format_t format;\n  unsigned int channels;\n\n  if (cairo_surface_status(surface)) {\n    return;\n  }\n\n  uint8_t *data = cairo_image_surface_get_data(surface);\n  format = cairo_image_surface_get_format(surface);\n  const int width = cairo_image_surface_get_width(surface);\n  const int height = cairo_image_surface_get_height(surface);\n  const int stride = cairo_image_surface_get_stride(surface);\n\n  if (format == CAIRO_FORMAT_ARGB32) {\n    channels = 4;\n  } else {\n    return;\n  }\n\n  horzBlur = (uint32_t *)(g_malloc(sizeof(uint32_t) * height * stride));\n  TICK();\n  uint32_t sum = 0;\n  kernel = create_kernel(radius, deviation, &sum);\n  TICK_N(\"BLUR: kernel\");\n\n  /* Horizontal pass. */\n  uint32_t *horzBlur_ptr = horzBlur;\n  for (int iY = 0; iY < height; iY++) {\n    const int iYs = iY * stride;\n    for (int iX = 0; iX < width; iX++) {\n      uint32_t red = 0;\n      uint32_t green = 0;\n      uint32_t blue = 0;\n      uint32_t alpha = 0;\n      int offset = (int)(kernel[0]) / -2;\n\n      for (int i = 0; i < (int)(kernel[0]); i++) {\n        int x = iX + offset;\n\n        if (x < 0 || x >= width) {\n          offset++;\n          continue;\n        }\n\n        uint8_t *dataPtr = &data[iYs + x * channels];\n        const uint32_t kernip1 = kernel[i + 1];\n\n        blue += kernip1 * dataPtr[0];\n        green += kernip1 * dataPtr[1];\n        red += kernip1 * dataPtr[2];\n        alpha += kernip1 * dataPtr[3];\n        offset++;\n      }\n\n      *horzBlur_ptr++ = blue / sum;\n      *horzBlur_ptr++ = green / sum;\n      *horzBlur_ptr++ = red / sum;\n      *horzBlur_ptr++ = alpha / sum;\n    }\n  }\n  TICK_N(\"BLUR: hori\");\n\n  /* Vertical pass. */\n  for (int iY = 0; iY < height; iY++) {\n    for (int iX = 0; iX < width; iX++) {\n      uint32_t red = 0;\n      uint32_t green = 0;\n      uint32_t blue = 0;\n      uint32_t alpha = 0;\n      int offset = (int)(kernel[0]) / -2;\n\n      const int iXs = iX * channels;\n      for (int i = 0; i < (int)(kernel[0]); i++) {\n        int y = iY + offset;\n\n        if (y < 0 || y >= height) {\n          offset++;\n          continue;\n        }\n\n        uint32_t *dataPtr = &horzBlur[y * stride + iXs];\n        const uint32_t kernip1 = kernel[i + 1];\n\n        blue += kernip1 * dataPtr[0];\n        green += kernip1 * dataPtr[1];\n        red += kernip1 * dataPtr[2];\n        alpha += kernip1 * dataPtr[3];\n\n        offset++;\n      }\n\n      *data++ = blue / sum;\n      *data++ = green / sum;\n      *data++ = red / sum;\n      *data++ = alpha / sum;\n    }\n  }\n  TICK_N(\"BLUR: vert\");\n\n  free(kernel);\n  free(horzBlur);\n\n  return;\n}\n\ncairo_surface_t *x11_helper_get_screenshot_surface_window(xcb_window_t window,\n                                                          int size) {\n  xcb_get_geometry_cookie_t cookie;\n  xcb_get_geometry_reply_t *reply;\n\n  cookie = xcb_get_geometry(xcb->connection, window);\n  reply = xcb_get_geometry_reply(xcb->connection, cookie, NULL);\n  if (reply == NULL) {\n    return NULL;\n  }\n\n  xcb_get_window_attributes_cookie_t attributesCookie =\n      xcb_get_window_attributes(xcb->connection, window);\n  xcb_get_window_attributes_reply_t *attributes =\n      xcb_get_window_attributes_reply(xcb->connection, attributesCookie, NULL);\n  if (attributes == NULL || (attributes->map_state != XCB_MAP_STATE_VIEWABLE)) {\n    free(reply);\n    if (attributes) {\n      free(attributes);\n    }\n    return NULL;\n  }\n  // Create a cairo surface for the window.\n  xcb_visualtype_t *vt = lookup_visual(xcb->screen, attributes->visual);\n  free(attributes);\n\n  cairo_surface_t *t = cairo_xcb_surface_create(xcb->connection, window, vt,\n                                                reply->width, reply->height);\n\n  if (cairo_surface_status(t) != CAIRO_STATUS_SUCCESS) {\n    cairo_surface_destroy(t);\n    free(reply);\n    return NULL;\n  }\n\n  // Scale the image, as we don't want to keep large one around.\n  int max = MAX(reply->width, reply->height);\n  double scale = (double)size / max;\n\n  cairo_surface_t *s2 = cairo_surface_create_similar_image(\n      t, CAIRO_FORMAT_ARGB32, reply->width * scale, reply->height * scale);\n  free(reply);\n\n  if (cairo_surface_status(s2) != CAIRO_STATUS_SUCCESS) {\n    cairo_surface_destroy(t);\n    return NULL;\n  }\n  // Paint it in.\n  cairo_t *d = cairo_create(s2);\n  cairo_scale(d, scale, scale);\n  cairo_set_source_surface(d, t, 0, 0);\n  cairo_paint(d);\n  cairo_destroy(d);\n\n  cairo_surface_destroy(t);\n  return s2;\n}\n/**\n * Holds for each supported modifier the possible modifier mask.\n * Check x11_mod_masks[MODIFIER]&mask != 0 to see if MODIFIER is activated.\n */\ncairo_surface_t *x11_helper_get_screenshot_surface(void) {\n  return cairo_xcb_surface_create(xcb->connection, xcb_stuff_get_root_window(),\n                                  root_visual, xcb->screen->width_in_pixels,\n                                  xcb->screen->height_in_pixels);\n}\n\nstatic xcb_pixmap_t get_root_pixmap(xcb_connection_t *c, xcb_screen_t *screen,\n                                    xcb_atom_t atom) {\n  xcb_get_property_cookie_t cookie;\n  xcb_get_property_reply_t *reply;\n  xcb_pixmap_t rootpixmap = XCB_NONE;\n\n  cookie = xcb_get_property(c, 0, screen->root, atom, XCB_ATOM_PIXMAP, 0, 1);\n\n  reply = xcb_get_property_reply(c, cookie, NULL);\n\n  if (reply) {\n    if (xcb_get_property_value_length(reply) == sizeof(xcb_pixmap_t)) {\n      memcpy(&rootpixmap, xcb_get_property_value(reply), sizeof(xcb_pixmap_t));\n    }\n    free(reply);\n  }\n\n  return rootpixmap;\n}\n\ncairo_surface_t *x11_helper_get_bg_surface(void) {\n  xcb_pixmap_t pm =\n      get_root_pixmap(xcb->connection, xcb->screen, netatoms[ESETROOT_PMAP_ID]);\n  if (pm == XCB_NONE) {\n    return NULL;\n  }\n  return cairo_xcb_surface_create(xcb->connection, pm, root_visual,\n                                  xcb->screen->width_in_pixels,\n                                  xcb->screen->height_in_pixels);\n}\n\n// retrieve a text property from a window\n// technically we could use window_get_prop(), but this is better for character\n// set support\nchar *window_get_text_prop(xcb_window_t w, xcb_atom_t atom) {\n  xcb_get_property_cookie_t c = xcb_get_property(\n      xcb->connection, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);\n  xcb_get_property_reply_t *r =\n      xcb_get_property_reply(xcb->connection, c, NULL);\n  if (r) {\n    if (xcb_get_property_value_length(r) > 0) {\n      char *str = NULL;\n      if (r->type == netatoms[UTF8_STRING]) {\n        str = g_strndup(xcb_get_property_value(r),\n                        xcb_get_property_value_length(r));\n      } else if (r->type == netatoms[STRING]) {\n        str = rofi_latin_to_utf8_strdup(xcb_get_property_value(r),\n                                        xcb_get_property_value_length(r));\n      } else {\n        str = g_strdup(\"Invalid encoding.\");\n      }\n\n      free(r);\n      return str;\n    }\n    free(r);\n  }\n  return NULL;\n}\n\nvoid window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms,\n                          int count) {\n  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, w, prop,\n                      XCB_ATOM_ATOM, 32, count, atoms);\n}\n\n/****\n * Code used to get monitor layout.\n */\n\n/**\n * Free monitor structure.\n */\nstatic void x11_monitor_free(workarea *m) {\n  g_free(m->name);\n  g_free(m);\n}\n\nstatic void x11_monitors_free(void) {\n  while (xcb->monitors != NULL) {\n    workarea *m = xcb->monitors;\n    xcb->monitors = m->next;\n    x11_monitor_free(m);\n  }\n}\n\n/**\n * Quick function that tries to fix the size (for dpi calculation)\n * when monitor is rotate. This assumes the density is kinda equal in both X/Y\n * direction.\n */\nstatic void x11_workarea_fix_rotation(workarea *w) {\n  double ratio_res = w->w / (double)w->h;\n  double ratio_size = w->mw / (double)w->mh;\n\n  if ((ratio_res < 1.0 && ratio_size > 1.0) ||\n      (ratio_res > 1.0 && ratio_size < 1.0)) {\n    // Oposite ratios, swap them.\n    int nh = w->mw;\n    w->mw = w->mh;\n    w->mh = nh;\n  }\n}\n/**\n * Create monitor based on output id\n */\nstatic workarea *x11_get_monitor_from_output(xcb_randr_output_t out) {\n  xcb_randr_get_output_info_reply_t *op_reply;\n  xcb_randr_get_crtc_info_reply_t *crtc_reply;\n  xcb_randr_get_output_info_cookie_t it =\n      xcb_randr_get_output_info(xcb->connection, out, XCB_CURRENT_TIME);\n  op_reply = xcb_randr_get_output_info_reply(xcb->connection, it, NULL);\n  if (op_reply->crtc == XCB_NONE) {\n    free(op_reply);\n    return NULL;\n  }\n  xcb_randr_get_crtc_info_cookie_t ct = xcb_randr_get_crtc_info(\n      xcb->connection, op_reply->crtc, XCB_CURRENT_TIME);\n  crtc_reply = xcb_randr_get_crtc_info_reply(xcb->connection, ct, NULL);\n  if (!crtc_reply) {\n    free(op_reply);\n    return NULL;\n  }\n  workarea *retv = g_malloc0(sizeof(workarea));\n  retv->x = crtc_reply->x;\n  retv->y = crtc_reply->y;\n  retv->w = crtc_reply->width;\n  retv->h = crtc_reply->height;\n\n  retv->mw = op_reply->mm_width;\n  retv->mh = op_reply->mm_height;\n  x11_workarea_fix_rotation(retv);\n\n  char *tname = (char *)xcb_randr_get_output_info_name(op_reply);\n  int tname_len = xcb_randr_get_output_info_name_length(op_reply);\n\n  retv->name = g_malloc0((tname_len + 1) * sizeof(char));\n  memcpy(retv->name, tname, tname_len);\n\n  free(crtc_reply);\n  free(op_reply);\n  return retv;\n}\n\n#if (((XCB_RANDR_MAJOR_VERSION >= RANDR_PREF_MAJOR_VERSION) &&                 \\\n      (XCB_RANDR_MINOR_VERSION >= RANDR_PREF_MINOR_VERSION)) ||                \\\n     XCB_RANDR_MAJOR_VERSION > RANDR_PREF_MAJOR_VERSION)\n/**\n * @param mon The randr monitor to parse.\n *\n * Create monitor based on xrandr monitor id.\n *\n * @returns A workarea representing the monitor mon\n */\nstatic workarea *\nx11_get_monitor_from_randr_monitor(xcb_randr_monitor_info_t *mon) {\n  // Query to the name of the monitor.\n  xcb_generic_error_t *err;\n  xcb_get_atom_name_cookie_t anc =\n      xcb_get_atom_name(xcb->connection, mon->name);\n  xcb_get_atom_name_reply_t *atom_reply =\n      xcb_get_atom_name_reply(xcb->connection, anc, &err);\n  if (err != NULL) {\n    g_warning(\"Could not get RandR monitor name: X11 error code %d\\n\",\n              err->error_code);\n    free(err);\n    return NULL;\n  }\n  workarea *retv = g_malloc0(sizeof(workarea));\n\n  // Is primary monitor.\n  retv->primary = mon->primary;\n\n  // Position and size.\n  retv->x = mon->x;\n  retv->y = mon->y;\n  retv->w = mon->width;\n  retv->h = mon->height;\n\n  // Physical\n  retv->mw = mon->width_in_millimeters;\n  retv->mh = mon->height_in_millimeters;\n  x11_workarea_fix_rotation(retv);\n\n  // Name\n  retv->name =\n      g_strdup_printf(\"%.*s\", xcb_get_atom_name_name_length(atom_reply),\n                      xcb_get_atom_name_name(atom_reply));\n\n  // Free name atom.\n  free(atom_reply);\n\n  return retv;\n}\n#endif\n\nstatic int x11_is_extension_present(const char *extension) {\n  xcb_query_extension_cookie_t randr_cookie =\n      xcb_query_extension(xcb->connection, strlen(extension), extension);\n\n  xcb_query_extension_reply_t *randr_reply =\n      xcb_query_extension_reply(xcb->connection, randr_cookie, NULL);\n\n  int present = randr_reply->present;\n\n  free(randr_reply);\n\n  return present;\n}\n\nstatic void x11_build_monitor_layout_xinerama(void) {\n  xcb_xinerama_query_screens_cookie_t screens_cookie =\n      xcb_xinerama_query_screens_unchecked(xcb->connection);\n\n  xcb_xinerama_query_screens_reply_t *screens_reply =\n      xcb_xinerama_query_screens_reply(xcb->connection, screens_cookie, NULL);\n\n  xcb_xinerama_screen_info_iterator_t screens_iterator =\n      xcb_xinerama_query_screens_screen_info_iterator(screens_reply);\n\n  for (; screens_iterator.rem > 0;\n       xcb_xinerama_screen_info_next(&screens_iterator)) {\n    workarea *w = g_malloc0(sizeof(workarea));\n\n    w->x = screens_iterator.data->x_org;\n    w->y = screens_iterator.data->y_org;\n    w->w = screens_iterator.data->width;\n    w->h = screens_iterator.data->height;\n\n    w->next = xcb->monitors;\n    xcb->monitors = w;\n  }\n\n  int index = 0;\n  for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n    iter->monitor_id = index++;\n  }\n\n  free(screens_reply);\n}\n\nstatic void x11_build_monitor_layout(void) {\n  if (xcb->monitors) {\n    return;\n  }\n  // If RANDR is not available, try Xinerama\n  if (!x11_is_extension_present(\"RANDR\")) {\n    // Check if xinerama is available.\n    if (x11_is_extension_present(\"XINERAMA\")) {\n      g_debug(\"Query XINERAMA for monitor layout.\");\n      x11_build_monitor_layout_xinerama();\n      return;\n    }\n    g_debug(\"No RANDR or Xinerama available for getting monitor layout.\");\n    return;\n  }\n  g_debug(\"Query RANDR for monitor layout.\");\n\n  g_debug(\"Randr XCB api version: %d.%d.\", XCB_RANDR_MAJOR_VERSION,\n          XCB_RANDR_MINOR_VERSION);\n#if (((XCB_RANDR_MAJOR_VERSION == RANDR_PREF_MAJOR_VERSION) &&                 \\\n      (XCB_RANDR_MINOR_VERSION >= RANDR_PREF_MINOR_VERSION)) ||                \\\n     XCB_RANDR_MAJOR_VERSION > RANDR_PREF_MAJOR_VERSION)\n  xcb_randr_query_version_cookie_t cversion = xcb_randr_query_version(\n      xcb->connection, RANDR_PREF_MAJOR_VERSION, RANDR_PREF_MINOR_VERSION);\n  xcb_randr_query_version_reply_t *rversion =\n      xcb_randr_query_version_reply(xcb->connection, cversion, NULL);\n  if (rversion) {\n    g_debug(\"Found randr version: %d.%d\", rversion->major_version,\n            rversion->minor_version);\n    // Check if we are 1.5 and up.\n    if (((rversion->major_version == RANDR_PREF_MAJOR_VERSION) &&\n         (rversion->minor_version >= RANDR_PREF_MINOR_VERSION)) ||\n        (rversion->major_version > RANDR_PREF_MAJOR_VERSION)) {\n      xcb_randr_get_monitors_cookie_t t =\n          xcb_randr_get_monitors(xcb->connection, xcb->screen->root, 1);\n      xcb_randr_get_monitors_reply_t *mreply =\n          xcb_randr_get_monitors_reply(xcb->connection, t, NULL);\n      if (mreply) {\n        xcb_randr_monitor_info_iterator_t iter =\n            xcb_randr_get_monitors_monitors_iterator(mreply);\n        while (iter.rem > 0) {\n          workarea *w = x11_get_monitor_from_randr_monitor(iter.data);\n          if (w) {\n            w->next = xcb->monitors;\n            xcb->monitors = w;\n          }\n          xcb_randr_monitor_info_next(&iter);\n        }\n        free(mreply);\n      }\n    }\n    free(rversion);\n  }\n#endif\n\n  // If no monitors found.\n  if (xcb->monitors == NULL) {\n    xcb_randr_get_screen_resources_current_reply_t *res_reply;\n    xcb_randr_get_screen_resources_current_cookie_t src;\n    src = xcb_randr_get_screen_resources_current(xcb->connection,\n                                                 xcb->screen->root);\n    res_reply = xcb_randr_get_screen_resources_current_reply(xcb->connection,\n                                                             src, NULL);\n    if (!res_reply) {\n      return; // just report error\n    }\n    int mon_num =\n        xcb_randr_get_screen_resources_current_outputs_length(res_reply);\n    xcb_randr_output_t *ops =\n        xcb_randr_get_screen_resources_current_outputs(res_reply);\n\n    // Get primary.\n    xcb_randr_get_output_primary_cookie_t pc =\n        xcb_randr_get_output_primary(xcb->connection, xcb->screen->root);\n    xcb_randr_get_output_primary_reply_t *pc_rep =\n        xcb_randr_get_output_primary_reply(xcb->connection, pc, NULL);\n\n    for (int i = mon_num - 1; i >= 0; i--) {\n      workarea *w = x11_get_monitor_from_output(ops[i]);\n      if (w) {\n        w->next = xcb->monitors;\n        xcb->monitors = w;\n        if (pc_rep && pc_rep->output == ops[i]) {\n          w->primary = TRUE;\n        }\n      }\n    }\n    // If exists, free primary output reply.\n    if (pc_rep) {\n      free(pc_rep);\n    }\n    free(res_reply);\n  }\n\n  // Number monitor\n  int index = 0;\n  for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n    iter->monitor_id = index++;\n  }\n}\n\nstatic void xcb_display_dump_monitor_layout(void) {\n  int is_term = isatty(fileno(stdout));\n  printf(\"Monitor layout:\\n\");\n  for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n    printf(\"%s              ID%s: %d\", (is_term) ? color_bold : \"\",\n           is_term ? color_reset : \"\", iter->monitor_id);\n    if (iter->primary) {\n      printf(\" (primary)\");\n    }\n    printf(\"\\n\");\n    printf(\"%s            name%s: %s\\n\", (is_term) ? color_bold : \"\",\n           is_term ? color_reset : \"\", iter->name);\n    printf(\"%s        position%s: %d,%d\\n\", (is_term) ? color_bold : \"\",\n           is_term ? color_reset : \"\", iter->x, iter->y);\n    printf(\"%s            size%s: %d,%d\\n\", (is_term) ? color_bold : \"\",\n           is_term ? color_reset : \"\", iter->w, iter->h);\n    if (iter->mw > 0 && iter->mh > 0) {\n      printf(\"%s            size%s: %dmm,%dmm  dpi: %.0f,%.0f\\n\",\n             (is_term) ? color_bold : \"\", is_term ? color_reset : \"\", iter->mw,\n             iter->mh, iter->w * 25.4 / (double)iter->mw,\n             iter->h * 25.4 / (double)iter->mh);\n    }\n    printf(\"\\n\");\n  }\n}\n\nstatic void xcb_display_startup_notification(RofiHelperExecuteContext *context,\n                                             GSpawnChildSetupFunc *child_setup,\n                                             gpointer *user_data) {\n  if (context == NULL) {\n    return;\n  }\n\n  SnLauncherContext *sncontext;\n\n  sncontext = sn_launcher_context_new(xcb->sndisplay, xcb->screen_nbr);\n\n  sn_launcher_context_set_name(sncontext, context->name);\n  sn_launcher_context_set_description(sncontext, context->description);\n  if (context->binary != NULL) {\n    sn_launcher_context_set_binary_name(sncontext, context->binary);\n  }\n  if (context->icon != NULL) {\n    sn_launcher_context_set_icon_name(sncontext, context->icon);\n  }\n  if (context->app_id != NULL) {\n    sn_launcher_context_set_application_id(sncontext, context->app_id);\n  }\n  if (context->wmclass != NULL) {\n    sn_launcher_context_set_wmclass(sncontext, context->wmclass);\n  }\n\n  xcb_get_property_cookie_t c;\n  unsigned int current_desktop = 0;\n\n  c = xcb_ewmh_get_current_desktop(&xcb->ewmh, xcb->screen_nbr);\n  if (xcb_ewmh_get_current_desktop_reply(&xcb->ewmh, c, &current_desktop,\n                                         NULL)) {\n    sn_launcher_context_set_workspace(sncontext, current_desktop);\n  }\n\n  sn_launcher_context_initiate(sncontext, \"rofi\", context->command,\n                               xcb->last_timestamp);\n\n  *child_setup = (GSpawnChildSetupFunc)sn_launcher_context_setup_child_process;\n  *user_data = sncontext;\n}\n\nstatic int monitor_get_dimension(int monitor_id, workarea *mon) {\n  memset(mon, 0, sizeof(workarea));\n  mon->w = xcb->screen->width_in_pixels;\n  mon->h = xcb->screen->height_in_pixels;\n\n  workarea *iter = NULL;\n  for (iter = xcb->monitors; iter; iter = iter->next) {\n    if (iter->monitor_id == monitor_id) {\n      *mon = *iter;\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n// find the dimensions of the monitor displaying point x,y\nstatic void monitor_dimensions(int x, int y, workarea *mon) {\n  if (mon == NULL) {\n    g_error(\"%s: mon == NULL\", __func__);\n    return;\n  }\n  memset(mon, 0, sizeof(workarea));\n  mon->w = xcb->screen->width_in_pixels;\n  mon->h = xcb->screen->height_in_pixels;\n\n  for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n    if (INTERSECT(x, y, iter->x, iter->y, iter->w, iter->h)) {\n      *mon = *iter;\n      break;\n    }\n  }\n}\n\n/**\n * @param root The X11 window used to find the pointer position. Usually the\n * root window.\n * @param x    The x position of the mouse [out]\n * @param y    The y position of the mouse [out]\n *\n * find mouse pointer location\n *\n * @returns TRUE when found, FALSE otherwise\n */\nstatic int pointer_get(xcb_window_t root, int *x, int *y) {\n  *x = 0;\n  *y = 0;\n  xcb_query_pointer_cookie_t c = xcb_query_pointer(xcb->connection, root);\n  xcb_query_pointer_reply_t *r =\n      xcb_query_pointer_reply(xcb->connection, c, NULL);\n  if (r) {\n    *x = r->root_x;\n    *y = r->root_y;\n    free(r);\n    return TRUE;\n  }\n\n  return FALSE;\n}\nstatic int monitor_active_from_winid(xcb_drawable_t id, workarea *mon) {\n  if (mon == NULL) {\n    g_error(\"%s: mon == NULL\", __func__);\n    return FALSE;\n  }\n  xcb_window_t root = xcb->screen->root;\n  xcb_get_geometry_cookie_t c = xcb_get_geometry(xcb->connection, id);\n  xcb_get_geometry_reply_t *r =\n      xcb_get_geometry_reply(xcb->connection, c, NULL);\n  if (r) {\n    xcb_translate_coordinates_cookie_t ct =\n        xcb_translate_coordinates(xcb->connection, id, root, r->x, r->y);\n    xcb_translate_coordinates_reply_t *t =\n        xcb_translate_coordinates_reply(xcb->connection, ct, NULL);\n    if (t) {\n      // place the menu above the window\n      // if some window is focused, place menu above window, else fall\n      // back to selected monitor.\n      mon->x = t->dst_x - r->x;\n      mon->y = t->dst_y - r->y;\n      mon->w = r->width;\n      mon->h = r->height;\n      free(r);\n      free(t);\n      return TRUE;\n    }\n    free(r);\n  }\n  return FALSE;\n}\nstatic int monitor_active_from_id_focused(int mon_id, workarea *mon) {\n  int retv = FALSE;\n  xcb_window_t active_window;\n  xcb_get_property_cookie_t awc;\n  if (mon == NULL) {\n    g_error(\"%s: mon == NULL\", __func__);\n    return retv;\n  }\n  awc = xcb_ewmh_get_active_window(&xcb->ewmh, xcb->screen_nbr);\n  if (!xcb_ewmh_get_active_window_reply(&xcb->ewmh, awc, &active_window,\n                                        NULL)) {\n    g_debug(\n        \"Failed to get active window, falling back to mouse location (-5).\");\n    return retv;\n  }\n  xcb_query_tree_cookie_t tree_cookie =\n      xcb_query_tree(xcb->connection, active_window);\n  xcb_query_tree_reply_t *tree_reply =\n      xcb_query_tree_reply(xcb->connection, tree_cookie, NULL);\n  if (!tree_reply) {\n    g_debug(\n        \"Failed to get parent window, falling back to mouse location (-5).\");\n    return retv;\n  }\n  // get geometry.\n  xcb_get_geometry_cookie_t c =\n      xcb_get_geometry(xcb->connection, active_window);\n  xcb_get_geometry_reply_t *r =\n      xcb_get_geometry_reply(xcb->connection, c, NULL);\n  if (!r) {\n    g_debug(\"Failed to get geometry of active window, falling back to mouse \"\n            \"location (-5).\");\n    free(tree_reply);\n    return retv;\n  }\n  if (tree_reply->parent != r->root) {\n    xcb_translate_coordinates_cookie_t ct = xcb_translate_coordinates(\n        xcb->connection, tree_reply->parent, r->root, r->x, r->y);\n    xcb_translate_coordinates_reply_t *t =\n        xcb_translate_coordinates_reply(xcb->connection, ct, NULL);\n    if (t) {\n      r->x = t->dst_x;\n      r->y = t->dst_y;\n      free(t);\n    } else {\n      g_debug(\"Failed to get translate position of active window, falling back \"\n              \"to mouse location (-5).\");\n      free(r);\n      free(tree_reply);\n      return retv;\n    }\n  }\n  if (mon_id == -2) {\n    // place the menu above the window\n    // if some window is focused, place menu above window, else fall\n    // back to selected monitor.\n    mon->x = r->x + r->border_width;\n    mon->y = r->y + r->border_width;\n    mon->w = r->width;\n    mon->h = r->height;\n    retv = TRUE;\n  } else if (mon_id == -4) {\n    g_debug(\"Find monitor at location: %d %d\", r->x, r->y);\n    monitor_dimensions(r->x, r->y, mon);\n    retv = TRUE;\n  }\n  g_debug(\"mon pos: %d %d %d-%d\", mon->x, mon->y, mon->w, mon->h);\n  free(r);\n  free(tree_reply);\n  return retv;\n}\nstatic int monitor_active_from_id(int mon_id, workarea *mon) {\n  xcb_window_t root = xcb->screen->root;\n  int x, y;\n  if (mon == NULL) {\n    g_error(\"%s: mon == NULL\", __func__);\n    return FALSE;\n  }\n  g_debug(\"Monitor id: %d\", mon_id);\n  // At mouse position.\n  if (mon_id == -3) {\n    if (pointer_get(root, &x, &y)) {\n      monitor_dimensions(x, y, mon);\n      mon->x = x;\n      mon->y = y;\n      return TRUE;\n    }\n  }\n  // Focused monitor\n  else if (mon_id == -1) {\n    g_debug(\"rofi on current monitor\");\n    // Get the current desktop.\n    unsigned int current_desktop = 0;\n    xcb_get_property_cookie_t gcdc;\n    gcdc = xcb_ewmh_get_current_desktop(&xcb->ewmh, xcb->screen_nbr);\n    if (xcb_ewmh_get_current_desktop_reply(&xcb->ewmh, gcdc, &current_desktop,\n                                           NULL)) {\n      g_debug(\"Found current desktop: %u\", current_desktop);\n      xcb_get_property_cookie_t c =\n          xcb_ewmh_get_desktop_viewport(&xcb->ewmh, xcb->screen_nbr);\n      xcb_ewmh_get_desktop_viewport_reply_t vp;\n      if (xcb_ewmh_get_desktop_viewport_reply(&xcb->ewmh, c, &vp, NULL)) {\n        g_debug(\"Found %d number of desktops\", vp.desktop_viewport_len);\n        if (current_desktop < vp.desktop_viewport_len) {\n          g_debug(\"Found viewport for desktop: %d %d\",\n                  vp.desktop_viewport[current_desktop].x,\n                  vp.desktop_viewport[current_desktop].y);\n          monitor_dimensions(vp.desktop_viewport[current_desktop].x,\n                             vp.desktop_viewport[current_desktop].y, mon);\n          g_debug(\"Found monitor @: %d %d %dx%d\", mon->x, mon->y, mon->w,\n                  mon->h);\n          xcb_ewmh_get_desktop_viewport_reply_wipe(&vp);\n          return TRUE;\n        } else {\n          g_debug(\"Viewport does not exist for current desktop: %d, falling \"\n                  \"back to mouse location (-5)\",\n                  current_desktop);\n        }\n        xcb_ewmh_get_desktop_viewport_reply_wipe(&vp);\n      } else {\n        g_debug(\"Failed to get viewport for current desktop: %d, falling back \"\n                \"to mouse location (-5).\",\n                current_desktop);\n      }\n    } else {\n      g_debug(\"Failed to get current desktop, falling back to mouse location \"\n              \"(-5).\");\n    }\n  } else if (mon_id == -2 || mon_id == -4) {\n    if (monitor_active_from_id_focused(mon_id, mon)) {\n      return TRUE;\n    }\n  }\n  // Monitor that has mouse pointer.\n  else if (mon_id == -5) {\n    if (pointer_get(root, &x, &y)) {\n      monitor_dimensions(x, y, mon);\n      return TRUE;\n    }\n    // This is our give up point.\n    return FALSE;\n  }\n  g_debug(\"Failed to find monitor, fall back to monitor showing mouse.\");\n  return monitor_active_from_id(-5, mon);\n}\n\n/** The cached monitor setup (mon_cache) is populated */\ngboolean mon_set = FALSE;\n/** cached monitor cache, to avoid multiple roundtrips to fetch this. */\nworkarea mon_cache = {\n    0,\n};\nstatic int xcb_display_monitor_active(workarea *mon) {\n  if (mon == NULL) {\n    g_error(\"%s: mon == NULL\", __func__);\n    return FALSE;\n  }\n  g_debug(\"Monitor active\");\n  if (mon_set) {\n    *mon = mon_cache;\n    return TRUE;\n  }\n  if (config.monitor != NULL) {\n    g_debug(\"Monitor lookup  by name : %s\", config.monitor);\n    for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n      if (g_strcmp0(config.monitor, iter->name) == 0) {\n        *mon = *iter;\n        mon_cache = *mon;\n        mon_set = TRUE;\n        return TRUE;\n      }\n    }\n  }\n  g_debug(\"Monitor lookup  by name failed: %s\", config.monitor);\n  // Grab primary.\n  if (g_strcmp0(config.monitor, \"primary\") == 0) {\n    for (workarea *iter = xcb->monitors; iter; iter = iter->next) {\n      if (iter->primary) {\n        *mon = *iter;\n        mon_cache = *mon;\n        mon_set = TRUE;\n        return TRUE;\n      }\n    }\n  }\n  if (g_str_has_prefix(config.monitor, \"wid:\")) {\n    char *end = NULL;\n    xcb_drawable_t win = g_ascii_strtoll(config.monitor + 4, &end, 0);\n    if (end != config.monitor) {\n      if (monitor_active_from_winid(win, mon)) {\n        mon_cache = *mon;\n        mon_set = TRUE;\n        return TRUE;\n      }\n    }\n  }\n  {\n    // IF fail, fall back to classic mode.\n    char *end = NULL;\n    gint64 mon_id = g_ascii_strtoll(config.monitor, &end, 0);\n    if (end != config.monitor) {\n      if (mon_id >= 0) {\n        if (monitor_get_dimension(mon_id, mon)) {\n          mon_cache = *mon;\n          mon_set = TRUE;\n          return TRUE;\n        }\n        g_warning(\"Failed to find selected monitor.\");\n      } else {\n        int val = monitor_active_from_id(mon_id, mon);\n        mon_cache = *mon;\n        mon_set = TRUE;\n        return val;\n      }\n    }\n  }\n  // Fallback.\n  monitor_dimensions(0, 0, mon);\n  mon_cache = *mon;\n  mon_set = TRUE;\n  return FALSE;\n}\n\nstatic bool get_atom_name(xcb_connection_t *conn, xcb_atom_t atom, char **out) {\n  xcb_get_atom_name_cookie_t cookie;\n  xcb_get_atom_name_reply_t *reply;\n  int length;\n  char *name;\n\n  if (atom == 0) {\n    *out = NULL;\n    return true;\n  }\n\n  cookie = xcb_get_atom_name(conn, atom);\n  reply = xcb_get_atom_name_reply(conn, cookie, NULL);\n  if (!reply)\n    return false;\n\n  length = xcb_get_atom_name_name_length(reply);\n  name = xcb_get_atom_name_name(reply);\n\n  (*out) = g_strndup(name, length);\n  if (!(*out)) {\n    free(reply);\n    return false;\n  }\n\n  free(reply);\n  return true;\n}\n\n/**\n * @param state Internal state of the menu.\n * @param xse   X selection event.\n *\n * Handle paste event.\n */\nstatic void rofi_view_paste(RofiViewState *state,\n                            xcb_selection_notify_event_t *xse) {\n  if (xse->property == XCB_ATOM_NONE) {\n    g_debug(\"Failed to convert selection\");\n  } else if (xse->property == xcb->ewmh.UTF8_STRING) {\n    gchar *text = window_get_text_prop(xse->requestor, xcb->ewmh.UTF8_STRING);\n    if (text != NULL && text[0] != '\\0') {\n      unsigned int dl = strlen(text);\n      // Strip new line\n      for (unsigned int i = 0; i < dl; i++) {\n        if (text[i] == '\\n') {\n          text[i] = '\\0';\n        }\n      }\n      rofi_view_handle_text(state, text);\n    }\n    g_free(text);\n  } else {\n    char *out = NULL;\n    if (get_atom_name(xcb->connection, xse->property, &out)) {\n      g_debug(\"rofi_view_paste: Got unknown atom: %s\", out);\n      g_free(out);\n    } else {\n      g_debug(\"rofi_view_paste: Got unknown, unnamed: %s\", out);\n    }\n  }\n}\n\nstatic gboolean\nx11_button_to_nk_bindings_button(guint32 x11_button,\n                                 NkBindingsMouseButton *button) {\n  switch (x11_button) {\n  case 1:\n    *button = NK_BINDINGS_MOUSE_BUTTON_PRIMARY;\n    break;\n  case 3:\n    *button = NK_BINDINGS_MOUSE_BUTTON_SECONDARY;\n    break;\n  case 2:\n    *button = NK_BINDINGS_MOUSE_BUTTON_MIDDLE;\n    break;\n  case 8:\n    *button = NK_BINDINGS_MOUSE_BUTTON_BACK;\n    break;\n  case 9:\n    *button = NK_BINDINGS_MOUSE_BUTTON_FORWARD;\n    break;\n  case 4:\n  case 5:\n  case 6:\n  case 7:\n    return FALSE;\n  default:\n    *button = NK_BINDINGS_MOUSE_BUTTON_EXTRA + x11_button;\n  }\n  return TRUE;\n}\n\nstatic gboolean x11_button_to_nk_bindings_scroll(guint32 x11_button,\n                                                 NkBindingsScrollAxis *axis,\n                                                 gint32 *steps) {\n  *steps = 1;\n  switch (x11_button) {\n  case 4:\n    *steps = -1;\n    rofi_fallthrough;\n  case 5:\n    *axis = NK_BINDINGS_SCROLL_AXIS_VERTICAL;\n    break;\n  case 6:\n    *steps = -1;\n    rofi_fallthrough;\n  case 7:\n    *axis = NK_BINDINGS_SCROLL_AXIS_HORIZONTAL;\n    break;\n  default:\n    return FALSE;\n  }\n  return TRUE;\n}\n\nstatic void rofi_key_press_event_handler(xcb_key_press_event_t *xkpe,\n                                         RofiViewState *state) {\n  gchar *text;\n  g_log(\"IMDKit\", G_LOG_LEVEL_DEBUG, \"press handler %d\", xkpe->detail);\n\n  xcb->last_timestamp = xkpe->time;\n  if (config.xserver_i300_workaround) {\n    text = nk_bindings_seat_handle_key_with_modmask(\n        xcb->bindings_seat, NULL, xkpe->state, xkpe->detail,\n        NK_BINDINGS_KEY_STATE_PRESS);\n  } else {\n    text = nk_bindings_seat_handle_key(xcb->bindings_seat, NULL, xkpe->detail,\n                                       NK_BINDINGS_KEY_STATE_PRESS);\n  }\n  if (text != NULL) {\n    rofi_view_handle_text(state, text);\n    g_free(text);\n  }\n}\n\nstatic void rofi_key_release_event_handler(xcb_key_release_event_t *xkre,\n                                           G_GNUC_UNUSED RofiViewState *state) {\n  g_log(\"IMDKit\", G_LOG_LEVEL_DEBUG, \"release handler %d\", xkre->detail);\n  xcb->last_timestamp = xkre->time;\n  nk_bindings_seat_handle_key(xcb->bindings_seat, NULL, xkre->detail,\n                              NK_BINDINGS_KEY_STATE_RELEASE);\n}\n\n/**\n * Process X11 events in the main-loop (gui-thread) of the application.\n */\nstatic void main_loop_x11_event_handler_view(xcb_generic_event_t *event) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return;\n  }\n\n  switch (event->response_type & ~0x80) {\n  case XCB_CLIENT_MESSAGE: {\n    xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;\n    xcb_atom_t atom = cme->data.data32[0];\n    xcb_timestamp_t time = cme->data.data32[1];\n    if (atom == netatoms[WM_TAKE_FOCUS]) {\n      xcb_set_input_focus(xcb->connection, XCB_INPUT_FOCUS_NONE, cme->window,\n                          time);\n      xcb_flush(xcb->connection);\n    }\n    break;\n  }\n  case XCB_DESTROY_NOTIFY: {\n    xcb_window_t win = ((xcb_destroy_notify_event_t *)event)->window;\n    if (win != rofi_view_get_window()) {\n#ifdef WINDOW_MODE\n      window_client_handle_signal(win, FALSE);\n#endif\n    } else {\n      g_main_loop_quit(xcb->main_loop);\n    }\n    break;\n  }\n  case XCB_CREATE_NOTIFY: {\n    xcb_window_t win = ((xcb_create_notify_event_t *)event)->window;\n    if (win != rofi_view_get_window()) {\n#ifdef WINDOW_MODE\n      window_client_handle_signal(win, TRUE);\n#endif\n    }\n    break;\n  }\n  case XCB_EXPOSE:\n    rofi_view_frame_callback();\n    break;\n  case XCB_CONFIGURE_NOTIFY: {\n    xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *)event;\n    rofi_view_temp_configure_notify(state, xce);\n    break;\n  }\n  case XCB_MOTION_NOTIFY: {\n    xcb_motion_notify_event_t *xme = (xcb_motion_notify_event_t *)event;\n    gboolean button_mask = xme->state & XCB_EVENT_MASK_BUTTON_1_MOTION;\n    rofi_view_handle_mouse_motion(state, xme->event_x, xme->event_y,\n                                  !button_mask && config.hover_select);\n    break;\n  }\n  case XCB_BUTTON_PRESS: {\n    xcb_button_press_event_t *bpe = (xcb_button_press_event_t *)event;\n    NkBindingsMouseButton button;\n    NkBindingsScrollAxis axis;\n    gint32 steps;\n\n    xcb->last_timestamp = bpe->time;\n    rofi_view_handle_mouse_motion(state, bpe->event_x, bpe->event_y, FALSE);\n    if (x11_button_to_nk_bindings_button(bpe->detail, &button)) {\n      nk_bindings_seat_handle_button(xcb->bindings_seat, NULL, button,\n                                     NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time);\n    } else if (x11_button_to_nk_bindings_scroll(bpe->detail, &axis, &steps)) {\n      nk_bindings_seat_handle_scroll(xcb->bindings_seat, NULL, axis, steps);\n    }\n    xcb->mouse_seen++;\n    break;\n  }\n  case XCB_SELECTION_CLEAR: {\n    g_debug(\"Selection Clear.\");\n    xcb_stuff_set_clipboard(NULL);\n  } break;\n  case XCB_SELECTION_REQUEST: {\n    g_debug(\"Selection Request.\");\n    xcb_selection_request_event_t *req = (xcb_selection_request_event_t *)event;\n    if (req->selection == netatoms[CLIPBOARD]) {\n      xcb_atom_t targets[2];\n      xcb_selection_notify_event_t selection_notify = {\n          .response_type = XCB_SELECTION_NOTIFY,\n          .sequence = 0,\n          .time = req->time,\n          .requestor = req->requestor,\n          .selection = req->selection,\n          .target = req->target,\n          .property = XCB_ATOM_NONE,\n      };\n      // If no clipboard, we return NONE.\n      if (xcb->clipboard) {\n        // Request for UTF-8\n        if (req->target == netatoms[UTF8_STRING]) {\n          g_debug(\"Selection Request UTF-8.\");\n          xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,\n                              req->requestor, req->property,\n                              netatoms[UTF8_STRING], 8,\n                              strlen(xcb->clipboard) + 1, xcb->clipboard);\n          selection_notify.property = req->property;\n        } else if (req->target == netatoms[TARGETS]) {\n          g_debug(\"Selection Request Targets.\");\n          // We currently only support UTF8 from clipboard. So indicate this.\n          targets[0] = netatoms[UTF8_STRING];\n          xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,\n                              req->requestor, req->property, XCB_ATOM_ATOM, 32,\n                              1, targets);\n          selection_notify.property = req->property;\n        }\n      }\n\n      xcb_send_event(xcb->connection,\n                     0, // propagate\n                     req->requestor, XCB_EVENT_MASK_NO_EVENT,\n                     (const char *)&selection_notify);\n      xcb_flush(xcb->connection);\n    }\n  } break;\n  case XCB_BUTTON_RELEASE: {\n    xcb_button_release_event_t *bre = (xcb_button_release_event_t *)event;\n    NkBindingsMouseButton button;\n\n    xcb->last_timestamp = bre->time;\n    if (x11_button_to_nk_bindings_button(bre->detail, &button)) {\n      nk_bindings_seat_handle_button(xcb->bindings_seat, NULL, button,\n                                     NK_BINDINGS_BUTTON_STATE_RELEASE,\n                                     bre->time);\n    }\n    if (config.click_to_exit == TRUE) {\n      if (!xcb->mouse_seen) {\n        rofi_view_temp_click_to_exit(state, bre->event);\n      }\n      xcb->mouse_seen--;\n    }\n    break;\n  }\n  // Paste event.\n  case XCB_SELECTION_NOTIFY:\n    rofi_view_paste(state, (xcb_selection_notify_event_t *)event);\n    break;\n  case XCB_KEYMAP_NOTIFY: {\n    xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *)event;\n    for (gint32 by = 0; by < 31; ++by) {\n      for (gint8 bi = 0; bi < 7; ++bi) {\n        if (kne->keys[by] & (1 << bi)) {\n          // X11 keycodes starts at 8\n          nk_bindings_seat_handle_key(xcb->bindings_seat, NULL,\n                                      (8 * by + bi) + 8,\n                                      NK_BINDINGS_KEY_STATE_PRESSED);\n        }\n      }\n    }\n    break;\n  }\n  case XCB_KEY_PRESS: {\n    xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *)event;\n#ifdef XCB_IMDKIT\n    if (config.enable_imdkit && xcb->ic) {\n      g_log(\"IMDKit\", G_LOG_LEVEL_DEBUG, \"press key %d to xim\", xkpe->detail);\n      xcb_xim_forward_event(xcb->im, xcb->ic, xkpe);\n      return;\n    } else\n#endif\n    {\n      rofi_key_press_event_handler(xkpe, state);\n    }\n    break;\n  }\n  case XCB_KEY_RELEASE: {\n    xcb_key_release_event_t *xkre = (xcb_key_release_event_t *)event;\n#ifdef XCB_IMDKIT\n    if (config.enable_imdkit && xcb->ic) {\n      g_log(\"IMDKit\", G_LOG_LEVEL_DEBUG, \"release key %d to xim\", xkre->detail);\n\n      // Check if the keysym is a modifier key (e.g., Shift, Ctrl, Alt). If it\n      // is, sleep for 5 milliseconds as a workaround for XCB XIM limitation.\n      // This sleep helps to ensure that XCB XIM can properly handle subsequent\n      // key events that may occur rapidly after a modifier key is pressed.\n      xcb_keysym_t sym = xcb_key_press_lookup_keysym(xcb->syms, xkre, 0);\n      if (xcb_is_modifier_key(sym)) {\n        struct timespec five_millis = {.tv_sec = 0, .tv_nsec = 5000000};\n        nanosleep(&five_millis, NULL);\n      }\n      xcb_xim_forward_event(xcb->im, xcb->ic, xkre);\n      return;\n    } else\n#endif\n    {\n      rofi_key_release_event_handler(xkre, state);\n    }\n    break;\n  }\n  default:\n    break;\n  }\n  rofi_view_maybe_update(state);\n}\n\n#ifdef XCB_IMDKIT\nvoid x11_event_handler_fowarding(G_GNUC_UNUSED xcb_xim_t *im,\n                                 G_GNUC_UNUSED xcb_xic_t ic,\n                                 xcb_key_press_event_t *event,\n                                 G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return;\n  }\n\n  uint8_t type = event->response_type & ~0x80;\n  if (type == XCB_KEY_PRESS) {\n    rofi_key_press_event_handler(event, state);\n  } else if (type == XCB_KEY_RELEASE) {\n    xcb_key_release_event_t *xkre = (xcb_key_release_event_t *)event;\n    rofi_key_release_event_handler(xkre, state);\n  }\n  rofi_view_maybe_update(state);\n}\n#endif\n\nstatic gboolean main_loop_x11_event_handler(xcb_generic_event_t *ev,\n                                            G_GNUC_UNUSED gpointer user_data) {\n  if (ev == NULL) {\n    int status = xcb_connection_has_error(xcb->connection);\n    if (status > 0) {\n      g_warning(\"The XCB connection to X server had a fatal error: %d\", status);\n      g_main_loop_quit(xcb->main_loop);\n      return G_SOURCE_REMOVE;\n    }\n    // DD: it seems this handler often gets dispatched while the queue in GWater\n    // is empty. resulting in a NULL for ev. This seems not an error.\n    // g_warning(\"main_loop_x11_event_handler: ev == NULL, status == %d\",\n    // status);\n    return G_SOURCE_CONTINUE;\n  }\n\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit && xcb->im && xcb_xim_filter_event(xcb->im, ev))\n    return G_SOURCE_CONTINUE;\n#endif\n\n  uint8_t type = ev->response_type & ~0x80;\n  if (type == xcb->xkb.first_event) {\n    switch (ev->pad0) {\n    case XCB_XKB_MAP_NOTIFY: {\n      struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device(\n          nk_bindings_seat_get_context(xcb->bindings_seat), xcb->connection,\n          xcb->xkb.device_id, 0);\n      struct xkb_state *state = xkb_x11_state_new_from_device(\n          keymap, xcb->connection, xcb->xkb.device_id);\n      nk_bindings_seat_update_keymap(xcb->bindings_seat, keymap, state);\n      xkb_keymap_unref(keymap);\n      xkb_state_unref(state);\n      break;\n    }\n    case XCB_XKB_STATE_NOTIFY: {\n      xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *)ev;\n      nk_bindings_seat_update_mask(xcb->bindings_seat, NULL, ksne->baseMods,\n                                   ksne->latchedMods, ksne->lockedMods,\n                                   ksne->baseGroup, ksne->latchedGroup,\n                                   ksne->lockedGroup);\n      rofi_view_maybe_update(rofi_view_get_active());\n      break;\n    }\n    }\n    return G_SOURCE_CONTINUE;\n  }\n  if (xcb->sndisplay != NULL) {\n    sn_xcb_display_process_event(xcb->sndisplay, ev);\n  }\n\n  main_loop_x11_event_handler_view(ev);\n  return G_SOURCE_CONTINUE;\n}\n\nstatic int take_pointer(xcb_window_t w, int iters) {\n  int i = 0;\n  while (TRUE) {\n    if (xcb_connection_has_error(xcb->connection)) {\n      g_warning(\"Connection has error\");\n      exit(EXIT_FAILURE);\n    }\n    xcb_grab_pointer_cookie_t cc =\n        xcb_grab_pointer(xcb->connection, 1, w, XCB_EVENT_MASK_BUTTON_RELEASE,\n                         XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, w, XCB_NONE,\n                         XCB_CURRENT_TIME);\n    xcb_grab_pointer_reply_t *r =\n        xcb_grab_pointer_reply(xcb->connection, cc, NULL);\n    if (r) {\n      if (r->status == XCB_GRAB_STATUS_SUCCESS) {\n        free(r);\n        return 1;\n      }\n      free(r);\n    }\n    if ((++i) > iters) {\n      break;\n    }\n    struct timespec del = {.tv_sec = 0, .tv_nsec = 1000000};\n    nanosleep(&del, NULL);\n  }\n  return 0;\n}\n\nstatic int take_keyboard(xcb_window_t w, int iters) {\n  int i = 0;\n  while (TRUE) {\n    if (xcb_connection_has_error(xcb->connection)) {\n      g_warning(\"Connection has error\");\n      exit(EXIT_FAILURE);\n    }\n    xcb_grab_keyboard_cookie_t cc =\n        xcb_grab_keyboard(xcb->connection, 1, w, XCB_CURRENT_TIME,\n                          XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);\n    xcb_grab_keyboard_reply_t *r =\n        xcb_grab_keyboard_reply(xcb->connection, cc, NULL);\n    if (r) {\n      if (r->status == XCB_GRAB_STATUS_SUCCESS) {\n        free(r);\n        return 1;\n      }\n      free(r);\n    }\n    if ((++i) > iters) {\n      break;\n    }\n    struct timespec del = {.tv_sec = 0, .tv_nsec = 1000000};\n    nanosleep(&del, NULL);\n  }\n  return 0;\n}\n\nstatic void release_keyboard(void) {\n  xcb_ungrab_keyboard(xcb->connection, XCB_CURRENT_TIME);\n}\nstatic void release_pointer(void) {\n  xcb_ungrab_pointer(xcb->connection, XCB_CURRENT_TIME);\n}\n\n/** X server error depth. to handle nested errors. */\nstatic int error_trap_depth = 0;\nstatic void error_trap_push(G_GNUC_UNUSED SnDisplay *display,\n                            G_GNUC_UNUSED xcb_connection_t *xdisplay) {\n  ++error_trap_depth;\n}\n\nstatic void error_trap_pop(G_GNUC_UNUSED SnDisplay *display,\n                           xcb_connection_t *xdisplay) {\n  if (error_trap_depth == 0) {\n    g_warning(\"Error trap underflow!\");\n    exit(EXIT_FAILURE);\n  }\n\n  xcb_flush(xdisplay);\n  --error_trap_depth;\n}\n\n/**\n * Fill in the list of frequently used X11 Atoms.\n */\nstatic void x11_create_frequently_used_atoms(void) {\n  // X atom values\n  for (int i = 0; i < NUM_NETATOMS; i++) {\n    xcb_intern_atom_cookie_t cc = xcb_intern_atom(\n        xcb->connection, 0, strlen(netatom_names[i]), netatom_names[i]);\n    xcb_intern_atom_reply_t *r =\n        xcb_intern_atom_reply(xcb->connection, cc, NULL);\n    if (r) {\n      netatoms[i] = r->atom;\n      free(r);\n    }\n  }\n}\n\nchar *x11_helper_get_window_manager(void) {\n  char *retv = NULL;\n  xcb_window_t wm_win = 0;\n  xcb_get_property_cookie_t cc = xcb_ewmh_get_supporting_wm_check_unchecked(\n      &xcb->ewmh, xcb_stuff_get_root_window());\n\n  if (xcb_ewmh_get_supporting_wm_check_reply(&xcb->ewmh, cc, &wm_win, NULL)) {\n    xcb_ewmh_get_utf8_strings_reply_t wtitle;\n    xcb_get_property_cookie_t cookie =\n        xcb_ewmh_get_wm_name_unchecked(&(xcb->ewmh), wm_win);\n    if (xcb_ewmh_get_wm_name_reply(&(xcb->ewmh), cookie, &wtitle, (void *)0)) {\n      if (wtitle.strings_len > 0) {\n        retv = g_strndup(wtitle.strings, wtitle.strings_len);\n      }\n      xcb_ewmh_get_utf8_strings_reply_wipe(&wtitle);\n    }\n  }\n  return retv;\n}\n\nstatic void x11_helper_discover_window_manager(void) {\n  xcb_window_t wm_win = 0;\n  xcb_get_property_cookie_t cc = xcb_ewmh_get_supporting_wm_check_unchecked(\n      &xcb->ewmh, xcb_stuff_get_root_window());\n\n  if (xcb_ewmh_get_supporting_wm_check_reply(&xcb->ewmh, cc, &wm_win, NULL)) {\n    xcb_ewmh_get_utf8_strings_reply_t wtitle;\n    xcb_get_property_cookie_t cookie =\n        xcb_ewmh_get_wm_name_unchecked(&(xcb->ewmh), wm_win);\n    if (xcb_ewmh_get_wm_name_reply(&(xcb->ewmh), cookie, &wtitle, (void *)0)) {\n      if (wtitle.strings_len > 0) {\n        // Copy the string and add terminating '\\0'.\n        char *str = g_strndup(wtitle.strings, wtitle.strings_len);\n        g_debug(\"Found window manager: |%s|\", str);\n        if (g_strcmp0(str, \"i3\") == 0) {\n          current_window_manager =\n              WM_DO_NOT_CHANGE_CURRENT_DESKTOP | WM_PANGO_WORKSPACE_NAMES;\n        }\n        g_free(str);\n      }\n      xcb_ewmh_get_utf8_strings_reply_wipe(&wtitle);\n    }\n  }\n}\n\nstatic gboolean xcb_display_setup(GMainLoop *main_loop, NkBindings *bindings) {\n  // Get DISPLAY, first env, then argument.\n  // We never modify display_str content.\n  char *display_str = (char *)g_getenv(\"DISPLAY\");\n  find_arg_str(\"-display\", &display_str);\n\n  xcb->main_loop = main_loop;\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit) {\n    xcb_compound_text_init();\n  }\n#endif\n  xcb->source = g_water_xcb_source_new(g_main_loop_get_context(xcb->main_loop),\n                                       display_str, &xcb->screen_nbr,\n                                       main_loop_x11_event_handler, NULL, NULL);\n  if (xcb->source == NULL) {\n    g_warning(\"Failed to open display: %s\", display_str);\n    return FALSE;\n  }\n  xcb->connection = g_water_xcb_source_get_connection(xcb->source);\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit) {\n    xcb->im = xcb_xim_create(xcb->connection, xcb->screen_nbr, NULL);\n    xcb->syms = xcb_key_symbols_alloc(xcb->connection);\n  } else {\n    xcb->im = NULL;\n    xcb->syms = NULL;\n  }\n#endif\n\n#ifdef XCB_IMDKIT\n#ifndef XCB_IMDKIT_1_0_3_LOWER\n  if (config.enable_imdkit) {\n    xcb_xim_set_use_compound_text(xcb->im, true);\n    xcb_xim_set_use_utf8_string(xcb->im, true);\n  }\n#endif\n#endif\n\n  TICK_N(\"Open Display\");\n\n  xcb->screen = xcb_aux_get_screen(xcb->connection, xcb->screen_nbr);\n\n  x11_build_monitor_layout();\n\n  xcb_intern_atom_cookie_t *ac =\n      xcb_ewmh_init_atoms(xcb->connection, &xcb->ewmh);\n  xcb_generic_error_t *errors = NULL;\n  xcb_ewmh_init_atoms_replies(&xcb->ewmh, ac, &errors);\n  if (errors) {\n    g_warning(\"Failed to create EWMH atoms\");\n    free(errors);\n  }\n  // Discover the current active window manager.\n  x11_helper_discover_window_manager();\n  TICK_N(\"Setup XCB\");\n\n  if (xkb_x11_setup_xkb_extension(\n          xcb->connection, XKB_X11_MIN_MAJOR_XKB_VERSION,\n          XKB_X11_MIN_MINOR_XKB_VERSION, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,\n          NULL, NULL, &xcb->xkb.first_event, NULL) < 0) {\n    g_warning(\"cannot setup XKB extension!\");\n    return FALSE;\n  }\n\n  xcb->xkb.device_id = xkb_x11_get_core_keyboard_device_id(xcb->connection);\n\n  enum {\n    required_events =\n        (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |\n         XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY),\n\n    required_nkn_details = (XCB_XKB_NKN_DETAIL_KEYCODES),\n\n    required_map_parts =\n        (XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS |\n         XCB_XKB_MAP_PART_MODIFIER_MAP | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |\n         XCB_XKB_MAP_PART_KEY_ACTIONS | XCB_XKB_MAP_PART_VIRTUAL_MODS |\n         XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP),\n\n    required_state_details =\n        (XCB_XKB_STATE_PART_MODIFIER_BASE | XCB_XKB_STATE_PART_MODIFIER_LATCH |\n         XCB_XKB_STATE_PART_MODIFIER_LOCK | XCB_XKB_STATE_PART_GROUP_BASE |\n         XCB_XKB_STATE_PART_GROUP_LATCH | XCB_XKB_STATE_PART_GROUP_LOCK),\n  };\n\n  static const xcb_xkb_select_events_details_t details = {\n      .affectNewKeyboard = required_nkn_details,\n      .newKeyboardDetails = required_nkn_details,\n      .affectState = required_state_details,\n      .stateDetails = required_state_details,\n  };\n  xcb_xkb_select_events(xcb->connection, xcb->xkb.device_id,\n                        required_events,    /* affectWhich */\n                        0,                  /* clear */\n                        required_events,    /* selectAll */\n                        required_map_parts, /* affectMap */\n                        required_map_parts, /* map */\n                        &details);\n\n  xcb->bindings_seat = nk_bindings_seat_new(bindings, XKB_CONTEXT_NO_FLAGS);\n  struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device(\n      nk_bindings_seat_get_context(xcb->bindings_seat), xcb->connection,\n      xcb->xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS);\n  if (keymap == NULL) {\n    g_warning(\"Failed to get Keymap for current keyboard device.\");\n    return FALSE;\n  }\n  struct xkb_state *state = xkb_x11_state_new_from_device(\n      keymap, xcb->connection, xcb->xkb.device_id);\n  if (state == NULL) {\n    g_warning(\"Failed to get state object for current keyboard device.\");\n    return FALSE;\n  }\n\n  nk_bindings_seat_update_keymap(xcb->bindings_seat, keymap, state);\n  xkb_state_unref(state);\n  xkb_keymap_unref(keymap);\n\n  // determine numlock mask so we can bind on keys with and without it\n  x11_create_frequently_used_atoms();\n\n  if (xcb_connection_has_error(xcb->connection)) {\n    g_warning(\"Connection has error\");\n    return FALSE;\n  }\n\n  uint32_t val[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY};\n  xcb_change_window_attributes(xcb->connection, xcb_stuff_get_root_window(),\n\t\t  XCB_CW_EVENT_MASK, val);\n  // startup not.\n  xcb->sndisplay =\n      sn_xcb_display_new(xcb->connection, error_trap_push, error_trap_pop);\n  if (xcb_connection_has_error(xcb->connection)) {\n    g_warning(\"Connection has error\");\n    return FALSE;\n  }\n\n  if (xcb->sndisplay != NULL) {\n    xcb->sncontext = sn_launchee_context_new_from_environment(xcb->sndisplay,\n                                                              xcb->screen_nbr);\n  }\n  if (xcb_connection_has_error(xcb->connection)) {\n    g_warning(\"Connection has error\");\n    return FALSE;\n  }\n\n  return TRUE;\n}\n\nstatic void x11_create_visual_and_colormap(void) {\n  xcb_depth_t *root_depth = NULL;\n  xcb_depth_iterator_t depth_iter;\n  for (depth_iter = xcb_screen_allowed_depths_iterator(xcb->screen);\n       depth_iter.rem; xcb_depth_next(&depth_iter)) {\n    xcb_depth_t *d = depth_iter.data;\n\n    xcb_visualtype_iterator_t visual_iter;\n    for (visual_iter = xcb_depth_visuals_iterator(d); visual_iter.rem;\n         xcb_visualtype_next(&visual_iter)) {\n      xcb_visualtype_t *v = visual_iter.data;\n      if ((v->bits_per_rgb_value == 8) && (d->depth == 32) &&\n          (v->_class == XCB_VISUAL_CLASS_TRUE_COLOR)) {\n        depth = d;\n        visual = v;\n      }\n      if (xcb->screen->root_visual == v->visual_id) {\n        root_depth = d;\n        root_visual = v;\n      }\n    }\n  }\n  if (visual != NULL) {\n    xcb_void_cookie_t c;\n    xcb_generic_error_t *e;\n    map = xcb_generate_id(xcb->connection);\n    c = xcb_create_colormap_checked(xcb->connection, XCB_COLORMAP_ALLOC_NONE,\n                                    map, xcb->screen->root, visual->visual_id);\n    e = xcb_request_check(xcb->connection, c);\n    if (e) {\n      depth = NULL;\n      visual = NULL;\n      free(e);\n    }\n  }\n\n  if (visual == NULL) {\n    depth = root_depth;\n    visual = root_visual;\n    map = xcb->screen->default_colormap;\n  }\n}\n\nstatic void x11_lookup_cursors(void) {\n  xcb_cursor_context_t *ctx;\n\n  if (xcb_cursor_context_new(xcb->connection, xcb->screen, &ctx) < 0) {\n    return;\n  }\n\n  for (int i = 0; i < NUM_CURSORS; ++i) {\n    cursors[i] = xcb_cursor_load_cursor(ctx, cursor_names[i].css_name);\n\n    if (cursors[i] == XCB_CURSOR_NONE) {\n      cursors[i] =\n          xcb_cursor_load_cursor(ctx, cursor_names[i].traditional_name);\n    }\n  }\n\n  xcb_cursor_context_free(ctx);\n}\n\n/** Retry count of grabbing keyboard. */\nunsigned int lazy_grab_retry_count_kb = 0;\n/** Retry count of grabbing pointer. */\nunsigned int lazy_grab_retry_count_pt = 0;\nstatic gboolean lazy_grab_pointer(G_GNUC_UNUSED gpointer data) {\n  // After 5 sec.\n  if (lazy_grab_retry_count_pt > (5 * 1000)) {\n    g_warning(\"Failed to grab pointer after %u times. Giving up.\",\n              lazy_grab_retry_count_pt);\n    return G_SOURCE_REMOVE;\n  }\n  if (take_pointer(xcb_stuff_get_root_window(), 0)) {\n    return G_SOURCE_REMOVE;\n  }\n  lazy_grab_retry_count_pt++;\n  return G_SOURCE_CONTINUE;\n}\nstatic gboolean lazy_grab_keyboard(G_GNUC_UNUSED gpointer data) {\n  // After 5 sec.\n  if (lazy_grab_retry_count_kb > (5 * 1000)) {\n    g_warning(\"Failed to grab keyboard after %u times. Giving up.\",\n              lazy_grab_retry_count_kb);\n    g_main_loop_quit(xcb->main_loop);\n    return G_SOURCE_REMOVE;\n  }\n  if (take_keyboard(xcb_stuff_get_root_window(), 0)) {\n    return G_SOURCE_REMOVE;\n  }\n  lazy_grab_retry_count_kb++;\n  return G_SOURCE_CONTINUE;\n}\n\nstatic gboolean xcb_display_late_setup(void) {\n  x11_create_visual_and_colormap();\n\n  x11_lookup_cursors();\n\n  /**\n   * Create window (without showing)\n   */\n  // Try to grab the keyboard as early as possible.\n  // We grab this using the rootwindow (as dmenu does it).\n  // this seems to result in the smallest delay for most people.\n  if (find_arg(\"-normal-window\") >= 0 || find_arg(\"-transient-window\") >= 0) {\n    return TRUE;\n  }\n  if (find_arg(\"-no-lazy-grab\") >= 0) {\n    if (!take_keyboard(xcb_stuff_get_root_window(), 500)) {\n      g_warning(\"Failed to grab keyboard, even after %d uS.\", 500 * 1000);\n      return FALSE;\n    }\n    if (!take_pointer(xcb_stuff_get_root_window(), 100)) {\n      g_warning(\"Failed to grab mouse pointer, even after %d uS.\", 100 * 1000);\n    }\n  } else {\n    if (!take_keyboard(xcb_stuff_get_root_window(), 0)) {\n      g_timeout_add(1, lazy_grab_keyboard, NULL);\n    }\n    if (!take_pointer(xcb_stuff_get_root_window(), 0)) {\n      g_timeout_add(1, lazy_grab_pointer, NULL);\n    }\n  }\n  return TRUE;\n}\n\nxcb_window_t xcb_stuff_get_root_window(void) { return xcb->screen->root; }\n\nstatic void xcb_display_early_cleanup(void) {\n  release_keyboard();\n  release_pointer();\n  xcb_flush(xcb->connection);\n}\n\nstatic void xcb_display_cleanup(void) {\n  if (xcb->connection == NULL) {\n    return;\n  }\n\n  g_debug(\"Cleaning up XCB and XKB\");\n\n  nk_bindings_seat_free(xcb->bindings_seat);\n  if (xcb->sncontext != NULL) {\n    sn_launchee_context_unref(xcb->sncontext);\n    xcb->sncontext = NULL;\n  }\n  if (xcb->sndisplay != NULL) {\n    sn_display_unref(xcb->sndisplay);\n    xcb->sndisplay = NULL;\n  }\n  x11_monitors_free();\n  xcb_ewmh_connection_wipe(&(xcb->ewmh));\n  xcb_flush(xcb->connection);\n  xcb_aux_sync(xcb->connection);\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit) {\n    xcb_xim_close(xcb->im);\n    xcb_xim_destroy(xcb->im);\n    xcb->im = NULL;\n  }\n#endif\n  g_water_xcb_source_free(xcb->source);\n  xcb->source = NULL;\n  xcb->connection = NULL;\n  xcb->screen = NULL;\n  xcb->screen_nbr = 0;\n}\n\nvoid x11_disable_decoration(xcb_window_t window) {\n  // Flag used to indicate we are setting the decoration type.\n  const uint32_t MWM_HINTS_DECORATIONS = (1 << 1);\n  // Motif property data structure\n  struct MotifWMHints {\n    uint32_t flags;\n    uint32_t functions;\n    uint32_t decorations;\n    int32_t inputMode;\n    uint32_t state;\n  };\n\n  struct MotifWMHints hints;\n  hints.flags = MWM_HINTS_DECORATIONS;\n  hints.decorations = 0;\n  hints.functions = 0;\n  hints.inputMode = 0;\n  hints.state = 0;\n\n  xcb_atom_t ha = netatoms[_MOTIF_WM_HINTS];\n  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, window, ha, ha,\n                      32, 5, &hints);\n}\n\nvoid x11_set_cursor(xcb_window_t window, X11CursorType type) {\n  if (type < 0 || type >= NUM_CURSORS) {\n    return;\n  }\n\n  if (cursors[type] == XCB_CURSOR_NONE) {\n    return;\n  }\n\n  xcb_change_window_attributes(xcb->connection, window, XCB_CW_CURSOR,\n                               &(cursors[type]));\n}\nvoid xcb_stuff_set_clipboard(char *data) {\n  g_free(xcb->clipboard);\n  xcb->clipboard = data;\n}\n\nstatic void xcb_display_set_input_focus(guint w) {\n  if (config.steal_focus != TRUE) {\n    xcb->focus_revert = 0;\n    return;\n  }\n  xcb_generic_error_t *error;\n  xcb_get_input_focus_reply_t *freply;\n  xcb_get_input_focus_cookie_t fcookie = xcb_get_input_focus(xcb->connection);\n  freply = xcb_get_input_focus_reply(xcb->connection, fcookie, &error);\n  if (error != NULL) {\n    g_warning(\"Could not get input focus (error %d), will revert focus to best \"\n              \"effort\",\n              error->error_code);\n    free(error);\n    xcb->focus_revert = 0;\n  } else {\n    xcb->focus_revert = freply->focus;\n  }\n  xcb_set_input_focus(xcb->connection, XCB_INPUT_FOCUS_POINTER_ROOT, w,\n                      XCB_CURRENT_TIME);\n  xcb_flush(xcb->connection);\n}\n\nstatic void xcb_display_revert_input_focus(void) {\n  if (xcb->focus_revert == 0) {\n    return;\n  }\n\n  xcb_set_input_focus(xcb->connection, XCB_INPUT_FOCUS_POINTER_ROOT,\n                      xcb->focus_revert, XCB_CURRENT_TIME);\n  xcb_flush(xcb->connection);\n}\n\nstatic guint xcb_display_scale(void) { return 1; }\n\nstatic const struct _view_proxy *xcb_display_view_proxy(void) {\n  return xcb_view_proxy;\n}\n\nstatic display_proxy display_ = {\n    .setup = xcb_display_setup,\n    .late_setup = xcb_display_late_setup,\n    .early_cleanup = xcb_display_early_cleanup,\n    .cleanup = xcb_display_cleanup,\n    .dump_monitor_layout = xcb_display_dump_monitor_layout,\n    .startup_notification = xcb_display_startup_notification,\n    .monitor_active = xcb_display_monitor_active,\n    .set_input_focus = xcb_display_set_input_focus,\n    .revert_input_focus = xcb_display_revert_input_focus,\n    .scale = xcb_display_scale,\n\n    .view = xcb_display_view_proxy,\n};\n\ndisplay_proxy *const xcb_proxy = &display_;\n"
  },
  {
    "path": "source/xcb/view.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n/** The Rofi View log domain */\n#define G_LOG_DOMAIN \"View\"\n\n#include <config.h>\n\n#include <errno.h>\n#include <locale.h>\n#include <signal.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n#ifdef XCB_IMDKIT\n#include <xcb-imdkit/encoding.h>\n#endif\n#include <xcb/xcb_ewmh.h>\n#include <xcb/xcb_icccm.h>\n#include <xcb/xkb.h>\n#include <xkbcommon/xkbcommon-x11.h>\n\n#include <cairo-xcb.h>\n#include <cairo.h>\n#include <gio/gio.h>\n\n/** Indicated we understand the startup notification api is not yet stable.*/\n#define SN_API_NOT_YET_FROZEN\n#include \"rofi.h\"\n#include <libsn/sn.h>\n\n#include \"settings.h\"\n#include \"timings.h\"\n\n#include \"display.h\"\n#include \"helper-theme.h\"\n#include \"helper.h\"\n#include \"mode.h\"\n#include \"modes/modes.h\"\n#include \"xcb-internal.h\"\n#include \"xrmoptions.h\"\n\n#include \"view-internal.h\"\n#include \"view.h\"\n\n#include \"theme.h\"\n\n#include \"xcb.h\"\n\nstatic int xcb_rofi_view_calculate_window_height(RofiViewState *state);\n\nstatic void xcb_rofi_view_set_window_title(const char *title);\n\nstatic void xcb_rofi_view_queue_redraw(void);\n\n#ifdef XCB_IMDKIT\nstatic void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,\n                              G_GNUC_UNUSED uint32_t flag, char *str,\n                              uint32_t length, G_GNUC_UNUSED uint32_t *keysym,\n                              G_GNUC_UNUSED size_t nKeySym,\n                              G_GNUC_UNUSED void *user_data);\nstatic void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,\n                             G_GNUC_UNUSED void *user_data);\nxcb_xim_im_callback xim_callback = {.forward_event =\n                                        x11_event_handler_fowarding,\n                                    .commit_string = xim_commit_string,\n                                    .disconnected = xim_disconnected};\n#endif\n\n/** Thread pool used for filtering */\nextern GThreadPool *tpool;\n\n/**\n * Structure holding cached state.\n */\nstatic struct {\n  /** surface containing the fake background. */\n  cairo_surface_t *fake_bg;\n  /** Draw context  for main window */\n  xcb_gcontext_t gc;\n  /** Main X11 side pixmap to draw on. */\n  xcb_pixmap_t edit_pixmap;\n  /** Cairo Surface for edit_pixmap */\n  cairo_surface_t *edit_surf;\n  /** Drawable context for edit_surf */\n  cairo_t *edit_draw;\n  /** Indicate that fake background should be drawn relative to the window */\n  int fake_bgrel;\n  /** Current work area */\n  workarea mon;\n  /** timeout for reloading */\n  guint idle_timeout;\n  /** debug counter for redraws */\n  unsigned long long count;\n  /** redraw idle time. */\n  guint repaint_source;\n  /** Window fullscreen */\n  gboolean fullscreen;\n  /** Cursor type */\n  X11CursorType cursor_type;\n} XcbState = {\n    .fake_bg = NULL,\n    .edit_surf = NULL,\n    .edit_draw = NULL,\n    .fake_bgrel = FALSE,\n    .idle_timeout = 0,\n    .count = 0L,\n    .repaint_source = 0,\n    .fullscreen = FALSE,\n};\n\nstatic void xcb_rofi_view_get_current_monitor(int *width, int *height) {\n  if (width) {\n    *width = XcbState.mon.w;\n  }\n  if (height) {\n    *height = XcbState.mon.h;\n  }\n}\n\n/**\n * Code used for benchmarking drawing the gui, this will keep updating the UI as\n * fast as possible.\n */\ngboolean do_bench = TRUE;\n\n/**\n * Internal structure that hold benchmarking information.\n */\nstatic struct {\n  /** timer used for timestamping. */\n  GTimer *time;\n  /** number of draws done. */\n  uint64_t draws;\n  /** previous timestamp */\n  double last_ts;\n  /** minimum draw time. */\n  double min;\n} BenchMark = {.time = NULL, .draws = 0, .last_ts = 0.0, .min = G_MAXDOUBLE};\n\nstatic gboolean bench_update(void) {\n  if (!config.benchmark_ui) {\n    return FALSE;\n  }\n  BenchMark.draws++;\n  if (BenchMark.time == NULL) {\n    BenchMark.time = g_timer_new();\n  }\n\n  if ((BenchMark.draws & 1023) == 0) {\n    double ts = g_timer_elapsed(BenchMark.time, NULL);\n    double fps = 1024 / (ts - BenchMark.last_ts);\n\n    if (fps < BenchMark.min) {\n      BenchMark.min = fps;\n    }\n    printf(\"current: %.2f fps, avg: %.2f fps, min: %.2f fps, %lu draws\\r\\n\",\n           fps, BenchMark.draws / ts, BenchMark.min, BenchMark.draws);\n\n    BenchMark.last_ts = ts;\n  }\n  return TRUE;\n}\n\nstatic gboolean xcb_rofi_view_repaint(G_GNUC_UNUSED void *data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state) {\n    // Repaint the view (if needed).\n    // After a resize the edit_pixmap surface might not contain anything\n    // anymore. If we already re-painted, this does nothing.\n\n    TICK_N(\"Update start\");\n    rofi_view_update(state, FALSE);\n    g_debug(\"expose event\");\n    TICK_N(\"Expose\");\n    xcb_copy_area(xcb->connection, XcbState.edit_pixmap, CacheState.main_window,\n                  XcbState.gc, 0, 0, 0, 0, state->width, state->height);\n    xcb_flush(xcb->connection);\n    TICK_N(\"flush\");\n    XcbState.repaint_source = 0;\n  }\n  return (bench_update() == TRUE) ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;\n}\n\n/**\n * @param state The handle to the view\n * @param qr    Indicate if queue_redraw should be called on changes.\n *\n * Update the state of the view. This involves filter state.\n */\nstatic void xcb_rofi_view_update(RofiViewState *state, gboolean qr) {\n  if (!widget_need_redraw(WIDGET(state->main_window))) {\n    return;\n  }\n  g_debug(\"Redraw view\");\n  TICK();\n  cairo_t *d = XcbState.edit_draw;\n  cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);\n  if (XcbState.fake_bg != NULL) {\n    if (XcbState.fake_bgrel) {\n      cairo_set_source_surface(d, XcbState.fake_bg, 0.0, 0.0);\n    } else {\n      cairo_set_source_surface(d, XcbState.fake_bg,\n                               (double)(XcbState.mon.x - state->x),\n                               (double)(XcbState.mon.y - state->y));\n    }\n  } else {\n    // Paint the background transparent.\n    cairo_set_source_rgba(d, 0, 0, 0, 0.0);\n  }\n  cairo_paint(d);\n\n  // Always paint as overlay over the background.\n  cairo_set_operator(d, CAIRO_OPERATOR_OVER);\n\n  TICK_N(\"Background\");\n  widget_draw(WIDGET(state->main_window), d);\n\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit) {\n    int x = widget_get_x_pos(&state->text->widget) +\n            textbox_get_cursor_x_pos(state->text);\n    int y = widget_get_y_pos(&state->text->widget) +\n            widget_get_height(&state->text->widget);\n    rofi_set_im_window_pos(x, y);\n  }\n#endif\n\n  TICK_N(\"widgets\");\n  cairo_surface_flush(XcbState.edit_surf);\n  if (qr) {\n    rofi_view_queue_redraw();\n  }\n}\n\n/**\n * Calculates the window position\n */\n/** Convert the old location to the new location type.\n * 123\n * 804\n * 765\n *\n * nw n ne\n * w  c e\n * sw s se\n */\nstatic const int loc_transtable[9] = {\n    WL_CENTER, WL_NORTH | WL_WEST, WL_NORTH, WL_NORTH | WL_EAST,\n    WL_EAST,   WL_SOUTH | WL_EAST, WL_SOUTH, WL_SOUTH | WL_WEST,\n    WL_WEST};\nstatic void xcb_rofi_view_calculate_window_position(RofiViewState *state) {\n  int location = rofi_theme_get_position(WIDGET(state->main_window), \"location\",\n                                         loc_transtable[config.location]);\n  int anchor =\n      rofi_theme_get_position(WIDGET(state->main_window), \"anchor\", location);\n\n  if (XcbState.fullscreen) {\n    state->x = XcbState.mon.x;\n    state->y = XcbState.mon.y;\n    return;\n  }\n  state->y = XcbState.mon.y + (XcbState.mon.h) / 2;\n  state->x = XcbState.mon.x + (XcbState.mon.w) / 2;\n  // Determine window location\n  switch (location) {\n  case WL_NORTH_WEST:\n    state->x = XcbState.mon.x;\n    rofi_fallthrough;\n  case WL_NORTH:\n    state->y = XcbState.mon.y;\n    break;\n  case WL_NORTH_EAST:\n    state->y = XcbState.mon.y;\n    rofi_fallthrough;\n  case WL_EAST:\n    state->x = XcbState.mon.x + XcbState.mon.w;\n    break;\n  case WL_SOUTH_EAST:\n    state->x = XcbState.mon.x + XcbState.mon.w;\n    rofi_fallthrough;\n  case WL_SOUTH:\n    state->y = XcbState.mon.y + XcbState.mon.h;\n    break;\n  case WL_SOUTH_WEST:\n    state->y = XcbState.mon.y + XcbState.mon.h;\n    rofi_fallthrough;\n  case WL_WEST:\n    state->x = XcbState.mon.x;\n    break;\n  case WL_CENTER:;\n    rofi_fallthrough;\n  default:\n    break;\n  }\n  switch (anchor) {\n  case WL_SOUTH_WEST:\n    state->y -= state->height;\n    break;\n  case WL_SOUTH:\n    state->x -= state->width / 2;\n    state->y -= state->height;\n    break;\n  case WL_SOUTH_EAST:\n    state->x -= state->width;\n    state->y -= state->height;\n    break;\n  case WL_NORTH_EAST:\n    state->x -= state->width;\n    break;\n  case WL_NORTH_WEST:\n    break;\n  case WL_NORTH:\n    state->x -= state->width / 2;\n    break;\n  case WL_EAST:\n    state->x -= state->width;\n    state->y -= state->height / 2;\n    break;\n  case WL_WEST:\n    state->y -= state->height / 2;\n    break;\n  case WL_CENTER:\n    state->y -= state->height / 2;\n    state->x -= state->width / 2;\n    break;\n  default:\n    break;\n  }\n  // Apply offset.\n  RofiDistance x = rofi_theme_get_distance(WIDGET(state->main_window),\n                                           \"x-offset\", config.x_offset);\n  RofiDistance y = rofi_theme_get_distance(WIDGET(state->main_window),\n                                           \"y-offset\", config.y_offset);\n  state->x += distance_get_pixel(x, ROFI_ORIENTATION_HORIZONTAL);\n  state->y += distance_get_pixel(y, ROFI_ORIENTATION_VERTICAL);\n}\n\nstatic void xcb_rofi_view_window_update_size(RofiViewState *state) {\n  if (state == NULL) {\n    return;\n  }\n  uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |\n                  XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;\n  uint32_t vals[] = {state->x, state->y, state->width, state->height};\n\n  // Display it.\n  xcb_configure_window(xcb->connection, CacheState.main_window, mask, vals);\n  cairo_destroy(XcbState.edit_draw);\n  cairo_surface_destroy(XcbState.edit_surf);\n\n  xcb_free_pixmap(xcb->connection, XcbState.edit_pixmap);\n  XcbState.edit_pixmap = xcb_generate_id(xcb->connection);\n  xcb_create_pixmap(xcb->connection, depth->depth, XcbState.edit_pixmap,\n                    CacheState.main_window, state->width, state->height);\n\n  XcbState.edit_surf =\n      cairo_xcb_surface_create(xcb->connection, XcbState.edit_pixmap, visual,\n                               state->width, state->height);\n  XcbState.edit_draw = cairo_create(XcbState.edit_surf);\n\n  g_debug(\"Re-size window based internal request: %dx%d.\", state->width,\n          state->height);\n  // Should wrap main window in a widget.\n  widget_resize(WIDGET(state->main_window), state->width, state->height);\n}\n\nstatic X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type) {\n  switch (type) {\n  case ROFI_CURSOR_DEFAULT:\n    return CURSOR_DEFAULT;\n\n  case ROFI_CURSOR_POINTER:\n    return CURSOR_POINTER;\n\n  case ROFI_CURSOR_TEXT:\n    return CURSOR_TEXT;\n  }\n\n  return CURSOR_DEFAULT;\n}\n\nstatic void xcb_rofi_view_set_cursor(RofiCursorType type) {\n  X11CursorType x11_type = rofi_cursor_type_to_x11_cursor_type(type);\n\n  if (x11_type == XcbState.cursor_type) {\n    return;\n  }\n\n  XcbState.cursor_type = x11_type;\n\n  x11_set_cursor(CacheState.main_window, x11_type);\n}\n\nstatic void xcb_rofi_view_ping_mouse(RofiViewState *state) {\n  xcb_query_pointer_cookie_t pointer_cookie =\n      xcb_query_pointer(xcb->connection, CacheState.main_window);\n  xcb_query_pointer_reply_t *pointer_reply =\n      xcb_query_pointer_reply(xcb->connection, pointer_cookie, NULL);\n\n  if (pointer_reply == NULL) {\n    return;\n  }\n\n  rofi_view_handle_mouse_motion(state, pointer_reply->win_x,\n                                pointer_reply->win_y, config.hover_select);\n\n  free(pointer_reply);\n}\n\nstatic gboolean xcb_rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {\n  RofiViewState *state = rofi_view_get_active();\n\n  if (state) {\n    // For UI update on this.\n    if (state->tb_total_rows) {\n      char *r = g_strdup_printf(\"%u\", mode_get_num_entries(state->sw));\n      textbox_text(state->tb_total_rows, r);\n      g_free(r);\n    }\n    state->reload = TRUE;\n    state->refilter = TRUE;\n    xcb_rofi_view_queue_redraw();\n  }\n  XcbState.idle_timeout = 0;\n  return G_SOURCE_REMOVE;\n}\n\nstatic void xcb_rofi_view_reload(void) {\n  // @TODO add check if current view is equal to the callee\n  if (XcbState.idle_timeout == 0) {\n    XcbState.idle_timeout =\n        g_timeout_add(1000 / 100, xcb_rofi_view_reload_idle, NULL);\n  }\n}\nstatic void xcb_rofi_view_queue_redraw(void) {\n  RofiViewState *state = rofi_view_get_active();\n\n  if (state && XcbState.repaint_source == 0) {\n    XcbState.count++;\n    g_debug(\"redraw %llu\", XcbState.count);\n    XcbState.repaint_source = g_idle_add_full(\n        G_PRIORITY_HIGH_IDLE, xcb_rofi_view_repaint, NULL, NULL);\n  }\n}\n\nstatic void\nxcb_rofi_view_setup_fake_transparency(widget *win,\n                                      const char *const fake_background) {\n  if (XcbState.fake_bg == NULL) {\n    cairo_surface_t *s = NULL;\n    /**\n     * Select Background to use for fake transparency.\n     * Current options: 'real', 'screenshot','background'\n     */\n    TICK_N(\"Fake start\");\n    if (g_strcmp0(fake_background, \"real\") == 0) {\n      return;\n    } else if (g_strcmp0(fake_background, \"screenshot\") == 0) {\n      s = x11_helper_get_screenshot_surface();\n    } else if (g_strcmp0(fake_background, \"background\") == 0) {\n      s = x11_helper_get_bg_surface();\n    } else {\n      char *fpath = rofi_expand_path(fake_background);\n      g_debug(\"Opening %s to use as background.\", fpath);\n      s = cairo_image_surface_create_from_png(fpath);\n      XcbState.fake_bgrel = TRUE;\n      g_free(fpath);\n    }\n    TICK_N(\"Get surface.\");\n    if (s != NULL) {\n      if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {\n        g_debug(\"Failed to open surface fake background: %s\",\n                cairo_status_to_string(cairo_surface_status(s)));\n        cairo_surface_destroy(s);\n        s = NULL;\n      } else {\n        XcbState.fake_bg = cairo_image_surface_create(\n            CAIRO_FORMAT_ARGB32, XcbState.mon.w, XcbState.mon.h);\n\n        int blur = rofi_theme_get_integer(WIDGET(win), \"blur\", 0);\n        cairo_t *dr = cairo_create(XcbState.fake_bg);\n        if (XcbState.fake_bgrel) {\n          cairo_set_source_surface(dr, s, 0, 0);\n        } else {\n          cairo_set_source_surface(dr, s, -XcbState.mon.x, -XcbState.mon.y);\n        }\n        cairo_paint(dr);\n        cairo_destroy(dr);\n        cairo_surface_destroy(s);\n        if (blur > 0) {\n          cairo_image_surface_blur(XcbState.fake_bg, (double)blur, 0);\n          TICK_N(\"BLUR\");\n        }\n      }\n    }\n    TICK_N(\"Fake transparency\");\n  }\n}\n\n#ifdef XCB_IMDKIT\nstatic void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,\n                              G_GNUC_UNUSED uint32_t flag, char *str,\n                              uint32_t length, G_GNUC_UNUSED uint32_t *keysym,\n                              G_GNUC_UNUSED size_t nKeySym,\n                              G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = rofi_view_get_active();\n  if (state == NULL) {\n    return;\n  }\n\n#ifndef XCB_IMDKIT_1_0_3_LOWER\n  if (xcb_xim_get_encoding(im) == XCB_XIM_UTF8_STRING) {\n    rofi_view_handle_text(state, str);\n  } else if (xcb_xim_get_encoding(im) == XCB_XIM_COMPOUND_TEXT) {\n    size_t newLength = 0;\n    char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);\n    if (utf8) {\n      rofi_view_handle_text(state, utf8);\n    }\n  }\n#else\n  size_t newLength = 0;\n  char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);\n  if (utf8) {\n    rofi_view_handle_text(state, utf8);\n  }\n#endif\n}\n\nstatic void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,\n                             G_GNUC_UNUSED void *user_data) {\n  xcb->ic = 0;\n}\n\nstatic void create_ic_callback(xcb_xim_t *im, xcb_xic_t new_ic,\n                               G_GNUC_UNUSED void *user_data) {\n  xcb->ic = new_ic;\n  if (xcb->ic) {\n    xcb_xim_set_ic_focus(im, xcb->ic);\n  }\n}\n\ngboolean rofi_set_im_window_pos(int new_x, int new_y) {\n  if (!xcb->ic)\n    return false;\n\n  static xcb_point_t spot = {.x = 0, .y = 0};\n  if (spot.x != new_x || spot.y != new_y) {\n    spot.x = new_x;\n    spot.y = new_y;\n    xcb_xim_nested_list nested = xcb_xim_create_nested_list(\n        xcb->im, XCB_XIM_XNSpotLocation, &spot, NULL);\n    xcb_xim_set_ic_values(xcb->im, xcb->ic, NULL, NULL, XCB_XIM_XNClientWindow,\n                          &CacheState.main_window, XCB_XIM_XNFocusWindow,\n                          &CacheState.main_window, XCB_XIM_XNPreeditAttributes,\n                          &nested, NULL);\n    free(nested.data);\n  }\n  return true;\n}\nstatic void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED void *user_data) {\n  RofiViewState *state = rofi_view_get_active();\n  uint32_t input_style = XCB_IM_PreeditPosition | XCB_IM_StatusArea;\n  xcb_point_t spot;\n  spot.x = widget_get_x_pos(&state->text->widget) +\n           textbox_get_cursor_x_pos(state->text);\n  spot.y = widget_get_y_pos(&state->text->widget) +\n           widget_get_height(&state->text->widget);\n  xcb_xim_nested_list nested =\n      xcb_xim_create_nested_list(im, XCB_XIM_XNSpotLocation, &spot, NULL);\n  xcb_xim_create_ic(\n      im, create_ic_callback, NULL, XCB_XIM_XNInputStyle, &input_style,\n      XCB_XIM_XNClientWindow, &CacheState.main_window, XCB_XIM_XNFocusWindow,\n      &CacheState.main_window, XCB_XIM_XNPreeditAttributes, &nested, NULL);\n  free(nested.data);\n}\n#endif\n\nstatic void xcb___create_window(MenuFlags menu_flags) {\n  input_history_initialize();\n\n  uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |\n                     XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |\n                     XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;\n  uint32_t xcb_event_masks =\n      XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |\n      XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |\n      XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |\n      XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |\n      XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;\n\n  uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,\n                       XCB_GRAVITY_STATIC,   XCB_BACKING_STORE_NOT_USEFUL,\n                       xcb_event_masks,      map};\n\n#ifdef XCB_IMDKIT\n  if (config.enable_imdkit) {\n    xcb_xim_set_im_callback(xcb->im, &xim_callback, NULL);\n\n    // Open connection to XIM server.\n    xcb_xim_open(xcb->im, open_xim_callback, true, NULL);\n  }\n#endif\n\n  xcb_window_t box_window = xcb_generate_id(xcb->connection);\n  xcb_void_cookie_t cc = xcb_create_window_checked(\n      xcb->connection, depth->depth, box_window, xcb_stuff_get_root_window(), 0,\n      0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual->visual_id, selmask,\n      selval);\n  xcb_generic_error_t *error;\n  error = xcb_request_check(xcb->connection, cc);\n  if (error) {\n    g_error(\"xcb_create_window() failed error=0x%x\\n\", error->error_code);\n    // g_error will cause the program to segfault.\n    // This is an unexpected error.\n    // exit(EXIT_FAILURE);\n  }\n\n  TICK_N(\"xcb create window\");\n  XcbState.gc = xcb_generate_id(xcb->connection);\n  xcb_create_gc(xcb->connection, XcbState.gc, box_window, 0, 0);\n\n  TICK_N(\"xcb create gc\");\n  // Create a drawable.\n  XcbState.edit_pixmap = xcb_generate_id(xcb->connection);\n  xcb_create_pixmap(xcb->connection, depth->depth, XcbState.edit_pixmap,\n                    CacheState.main_window, 200, 100);\n\n  XcbState.edit_surf = cairo_xcb_surface_create(\n      xcb->connection, XcbState.edit_pixmap, visual, 200, 100);\n  XcbState.edit_draw = cairo_create(XcbState.edit_surf);\n\n  TICK_N(\"create cairo surface\");\n  // Set up pango context.\n  cairo_font_options_t *fo = cairo_font_options_create();\n  // Take font description from xlib surface\n  cairo_surface_get_font_options(XcbState.edit_surf, fo);\n  // TODO should we update the drawable each time?\n  PangoContext *p = pango_cairo_create_context(XcbState.edit_draw);\n  // Set the font options from the xlib surface\n  pango_cairo_context_set_font_options(p, fo);\n  TICK_N(\"pango cairo font setup\");\n\n  CacheState.main_window = box_window;\n  CacheState.flags = menu_flags;\n  monitor_active(&(XcbState.mon));\n  // Setup dpi\n  if (config.dpi > 1) {\n    PangoFontMap *font_map = pango_cairo_font_map_get_default();\n    pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,\n                                        (double)config.dpi);\n  } else if (config.dpi == 0 || config.dpi == 1) {\n    // Auto-detect mode.\n    double dpi = 96;\n    if (XcbState.mon.mh > 0 && config.dpi == 1) {\n      dpi = (XcbState.mon.h * 25.4) / (double)(XcbState.mon.mh);\n    } else {\n      dpi = (xcb->screen->height_in_pixels * 25.4) /\n            (double)(xcb->screen->height_in_millimeters);\n    }\n\n    g_debug(\"Auto-detected DPI: %.2lf\", dpi);\n    PangoFontMap *font_map = pango_cairo_font_map_get_default();\n    pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);\n    config.dpi = dpi;\n  } else {\n    // default pango is 96.\n    PangoFontMap *font_map = pango_cairo_font_map_get_default();\n    config.dpi =\n        pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);\n  }\n  // Setup font.\n  // Dummy widget.\n  box *win = box_create(NULL, \"window\", ROFI_ORIENTATION_HORIZONTAL);\n  const char *font =\n      rofi_theme_get_string(WIDGET(win), \"font\", config.menu_font);\n  if (font) {\n    PangoFontDescription *pfd = pango_font_description_from_string(font);\n    if (helper_validate_font(pfd, font)) {\n      pango_context_set_font_description(p, pfd);\n    }\n    pango_font_description_free(pfd);\n  }\n  PangoLanguage *l = pango_language_get_default();\n  pango_context_set_language(p, l);\n  TICK_N(\"configure font\");\n\n  // Tell textbox to use this context.\n  textbox_set_pango_context(font, p);\n  // cleanup\n  g_object_unref(p);\n  cairo_font_options_destroy(fo);\n\n  TICK_N(\"textbox setup\");\n  // // make it an unmanaged window\n  if (((menu_flags & MENU_TRANSIENT_WINDOW) != 0)) {\n    xcb_atom_t atoms[] = {xcb->ewmh._NET_WM_STATE_MODAL};\n\n    window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE, atoms,\n                         sizeof(atoms) / sizeof(xcb_atom_t));\n    window_set_atom_prop(box_window, xcb->ewmh._NET_WM_WINDOW_TYPE,\n                         &(xcb->ewmh._NET_WM_WINDOW_TYPE_UTILITY), 1);\n    x11_disable_decoration(box_window);\n\n    xcb_window_t active_window;\n    xcb_get_property_cookie_t awc;\n    awc = xcb_ewmh_get_active_window(&xcb->ewmh, xcb->screen_nbr);\n\n    if (xcb_ewmh_get_active_window_reply(&xcb->ewmh, awc, &active_window,\n                                         NULL)) {\n      xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, box_window,\n                          XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1,\n                          &active_window);\n    }\n  } else if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {\n    window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE,\n                         &(xcb->ewmh._NET_WM_STATE_ABOVE), 1);\n    uint32_t values[] = {1};\n    xcb_change_window_attributes(xcb->connection, box_window,\n                                 XCB_CW_OVERRIDE_REDIRECT, values);\n  } else {\n    window_set_atom_prop(box_window, xcb->ewmh._NET_WM_WINDOW_TYPE,\n                         &(xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);\n    x11_disable_decoration(box_window);\n  }\n\n  TICK_N(\"setup window attributes\");\n  XcbState.fullscreen =\n      rofi_theme_get_boolean(WIDGET(win), \"fullscreen\", FALSE);\n  if (XcbState.fullscreen) {\n    xcb_atom_t atoms[] = {xcb->ewmh._NET_WM_STATE_FULLSCREEN,\n                          xcb->ewmh._NET_WM_STATE_ABOVE};\n    window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE, atoms,\n                         sizeof(atoms) / sizeof(xcb_atom_t));\n  }\n\n  xcb_atom_t protocols[] = {netatoms[WM_TAKE_FOCUS]};\n  xcb_icccm_set_wm_protocols(xcb->connection, box_window,\n                             xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),\n                             protocols);\n\n  TICK_N(\"setup window fullscreen\");\n  // Set the WM_NAME\n  xcb_rofi_view_set_window_title(\"rofi\");\n  const char wm_class_name[] = \"rofi\\0Rofi\";\n  xcb_icccm_set_wm_class(xcb->connection, box_window, sizeof(wm_class_name),\n                         wm_class_name);\n\n  TICK_N(\"setup window name and class\");\n  const char *transparency =\n      rofi_theme_get_string(WIDGET(win), \"transparency\", NULL);\n  if (transparency) {\n    xcb_rofi_view_setup_fake_transparency(WIDGET(win), transparency);\n  }\n  if (xcb->sncontext != NULL) {\n    sn_launchee_context_setup_window(xcb->sncontext, CacheState.main_window);\n  }\n  TICK_N(\"setup startup notification\");\n  widget_free(WIDGET(win));\n  TICK_N(\"done\");\n\n  // Set the PID.\n  pid_t pid = getpid();\n  xcb_ewmh_set_wm_pid(&(xcb->ewmh), CacheState.main_window, pid);\n\n  // Get hostname\n  const char *hostname = g_get_host_name();\n  char *ahost = g_hostname_to_ascii(hostname);\n  if (ahost != NULL) {\n    xcb_icccm_set_wm_client_machine(xcb->connection, CacheState.main_window,\n                                    XCB_ATOM_STRING, 8, strlen(ahost), ahost);\n    g_free(ahost);\n  }\n}\n\n/**\n * @param state Internal state of the menu.\n *\n * Calculate the width of the window and the width of an element.\n */\nstatic void xcb_rofi_view_calculate_window_width(RofiViewState *state) {\n  if (XcbState.fullscreen) {\n    state->width = XcbState.mon.w;\n    return;\n  }\n  // Calculate as float to stop silly, big rounding down errors.\n  state->width = (XcbState.mon.w / 100.0f) * DEFAULT_MENU_WIDTH;\n  // Use theme configured width, if set.\n  RofiDistance width = rofi_theme_get_distance(WIDGET(state->main_window),\n                                               \"width\", state->width);\n  state->width = distance_get_pixel(width, ROFI_ORIENTATION_HORIZONTAL);\n}\n\n/**\n * Handle window configure event.\n * Handles resizes.\n */\nstatic void\nxcb_rofi_view_temp_configure_notify(RofiViewState *state,\n                                    xcb_configure_notify_event_t *xce) {\n  if (xce->window == CacheState.main_window) {\n    if (state->x != xce->x || state->y != xce->y) {\n      state->x = xce->x;\n      state->y = xce->y;\n      widget_queue_redraw(WIDGET(state->main_window));\n    }\n    if (state->width != xce->width || state->height != xce->height) {\n      state->width = xce->width;\n      state->height = xce->height;\n\n      cairo_destroy(XcbState.edit_draw);\n      cairo_surface_destroy(XcbState.edit_surf);\n\n      xcb_free_pixmap(xcb->connection, XcbState.edit_pixmap);\n      XcbState.edit_pixmap = xcb_generate_id(xcb->connection);\n      xcb_create_pixmap(xcb->connection, depth->depth, XcbState.edit_pixmap,\n                        CacheState.main_window, state->width, state->height);\n\n      XcbState.edit_surf =\n          cairo_xcb_surface_create(xcb->connection, XcbState.edit_pixmap,\n                                   visual, state->width, state->height);\n      XcbState.edit_draw = cairo_create(XcbState.edit_surf);\n      g_debug(\"Re-size window based external request: %d %d\", state->width,\n              state->height);\n      widget_resize(WIDGET(state->main_window), state->width, state->height);\n    }\n  }\n}\n\n/**\n * Quit rofi on click (outside of view )\n */\nstatic void xcb_rofi_view_temp_click_to_exit(RofiViewState *state,\n                                             xcb_window_t target) {\n  if ((CacheState.flags & MENU_NORMAL_WINDOW) == 0) {\n    if (target != CacheState.main_window) {\n      state->quit = TRUE;\n      state->retv = MENU_CANCEL;\n    }\n  }\n}\n\nstatic void xcb_rofi_view_frame_callback(void) {\n  if (XcbState.repaint_source == 0) {\n    XcbState.count++;\n    g_debug(\"redraw %llu\", XcbState.count);\n    XcbState.repaint_source = g_idle_add_full(\n        G_PRIORITY_HIGH_IDLE, xcb_rofi_view_repaint, NULL, NULL);\n  }\n}\n\nstatic int xcb_rofi_view_calculate_window_height(RofiViewState *state) {\n  if (XcbState.fullscreen == TRUE) {\n    return XcbState.mon.h;\n  }\n\n  RofiDistance h =\n      rofi_theme_get_distance(WIDGET(state->main_window), \"height\", 0);\n  unsigned int height = distance_get_pixel(h, ROFI_ORIENTATION_VERTICAL);\n  // If height is set, return it.\n  if (height > 0) {\n    return height;\n  }\n  // Autosize based on widgets.\n  widget *main_window = WIDGET(state->main_window);\n  return widget_get_desired_height(main_window, state->width);\n}\n\nstatic void xcb_rofi_view_hide(void) {\n  if (CacheState.main_window != XCB_WINDOW_NONE) {\n    display_revert_input_focus();\n    xcb_unmap_window(xcb->connection, CacheState.main_window);\n    display_early_cleanup();\n  }\n}\n\nstatic void xcb_rofi_view_cleanup(void) {\n  // Clear clipboard data.\n  xcb_stuff_set_clipboard(NULL);\n  g_debug(\"Cleanup.\");\n  if (XcbState.idle_timeout > 0) {\n    g_source_remove(XcbState.idle_timeout);\n    XcbState.idle_timeout = 0;\n  }\n  if (CacheState.refilter_timeout > 0) {\n    g_source_remove(CacheState.refilter_timeout);\n    CacheState.refilter_timeout = 0;\n  }\n  if (CacheState.overlay_timeout) {\n    g_source_remove(CacheState.overlay_timeout);\n    CacheState.overlay_timeout = 0;\n  }\n  if (CacheState.user_timeout > 0) {\n    g_source_remove(CacheState.user_timeout);\n    CacheState.user_timeout = 0;\n  }\n  if (XcbState.repaint_source > 0) {\n    g_source_remove(XcbState.repaint_source);\n    XcbState.repaint_source = 0;\n  }\n  if (XcbState.fake_bg) {\n    cairo_surface_destroy(XcbState.fake_bg);\n    XcbState.fake_bg = NULL;\n  }\n  if (XcbState.edit_draw) {\n    cairo_destroy(XcbState.edit_draw);\n    XcbState.edit_draw = NULL;\n  }\n  if (XcbState.edit_surf) {\n    cairo_surface_destroy(XcbState.edit_surf);\n    XcbState.edit_surf = NULL;\n  }\n  if (CacheState.main_window != XCB_WINDOW_NONE) {\n    g_debug(\"Unmapping and free'ing window\");\n    xcb_unmap_window(xcb->connection, CacheState.main_window);\n    xcb_free_gc(xcb->connection, XcbState.gc);\n    xcb_free_pixmap(xcb->connection, XcbState.edit_pixmap);\n    xcb_destroy_window(xcb->connection, CacheState.main_window);\n    CacheState.main_window = XCB_WINDOW_NONE;\n  }\n  if (map != XCB_COLORMAP_NONE) {\n    xcb_free_colormap(xcb->connection, map);\n    map = XCB_COLORMAP_NONE;\n  }\n  xcb_flush(xcb->connection);\n  g_assert(g_queue_is_empty(&(CacheState.views)));\n\n  input_history_save();\n}\n\nstatic xcb_window_t xcb_rofi_view_get_window(void) {\n  return CacheState.main_window;\n}\n\nstatic void xcb_rofi_view_set_window_title(const char *title) {\n  ssize_t len = strlen(title);\n  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,\n                      CacheState.main_window, xcb->ewmh._NET_WM_NAME,\n                      xcb->ewmh.UTF8_STRING, 8, len, title);\n  xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,\n                      CacheState.main_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING,\n                      8, len, title);\n}\n\nstatic view_proxy view_ = {\n    .update = xcb_rofi_view_update,\n    .temp_configure_notify = xcb_rofi_view_temp_configure_notify,\n    .temp_click_to_exit = xcb_rofi_view_temp_click_to_exit,\n    .frame_callback = xcb_rofi_view_frame_callback,\n    .queue_redraw = xcb_rofi_view_queue_redraw,\n\n    .set_window_title = xcb_rofi_view_set_window_title,\n    .calculate_window_position = xcb_rofi_view_calculate_window_position,\n    .calculate_window_width = xcb_rofi_view_calculate_window_width,\n    .calculate_window_height = xcb_rofi_view_calculate_window_height,\n    .window_update_size = xcb_rofi_view_window_update_size,\n    .set_cursor = xcb_rofi_view_set_cursor,\n    .ping_mouse = xcb_rofi_view_ping_mouse,\n\n    .cleanup = xcb_rofi_view_cleanup,\n    .hide = xcb_rofi_view_hide,\n    .reload = xcb_rofi_view_reload,\n\n    .__create_window = xcb___create_window,\n    .get_window = xcb_rofi_view_get_window,\n    .get_current_monitor = xcb_rofi_view_get_current_monitor,\n\n    .set_size = NULL,\n    .get_size = NULL,\n};\n\nconst view_proxy *xcb_view_proxy = &view_;\n"
  },
  {
    "path": "source/xrmoptions.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n/** Log domain for this module */\n#define G_LOG_DOMAIN \"XrmOptions\"\n\n#include \"xrmoptions.h\"\n#include \"helper.h\"\n#include \"rofi-types.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include <ctype.h>\n#include <glib.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\nThemeWidget *rofi_configuration = NULL;\n\n/** Different sources of configuration. */\nconst char *const ConfigSourceStr[] = {\"Default\", \"File\", \"Rasi File\",\n                                       \"Commandline\", \"Don't Display\"};\n/** Enumerator of different sources of configuration. */\nenum ConfigSource {\n  CONFIG_DEFAULT = 0,\n  CONFIG_FILE = 1,\n  CONFIG_FILE_THEME = 2,\n  CONFIG_CMDLINE = 3,\n  CONFIG_NO_DISPLAY = 4\n};\n\ntypedef struct {\n  int32_t type;\n  enum ConfigSource source;\n  const char *name;\n  union {\n    unsigned int *num;\n    int *snum;\n    char **str;\n    void *pointer;\n    char *charc;\n  } value;\n  char *mem;\n  const char *comment;\n} XrmOption;\n/**\n * Map X resource and commandline options to internal options\n * Currently supports string, boolean and number (signed and unsigned).\n */\nstatic XrmOption xrmOptions[] = {\n    {xrm_String, CONFIG_DEFAULT, \"switchers\", {.str = &config.modes}, NULL, \"\"},\n    {xrm_String,\n     CONFIG_DEFAULT,\n     \"modi\",\n     {.str = &config.modes},\n     NULL,\n     \"Enabled modes\"},\n    {xrm_String,\n     CONFIG_DEFAULT,\n     \"modes\",\n     {.str = &config.modes},\n     NULL,\n     \"Enable modes\"},\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"font\",\n        {.str = &config.menu_font},\n        NULL,\n        \"Font to use\",\n    },\n    {\n        xrm_Number,\n        CONFIG_DEFAULT,\n        \"location\",\n        {.num = &config.location},\n        NULL,\n        \"Location on screen\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"wayland-layer\",\n        {.str = &config.wayland_layer},\n        NULL,\n        \"On Wayland, specifies the layer where rofi is rendered. \"\n        \"Available layers are background, bottom, top, overlay.\",\n    },\n    {\n        xrm_SNumber,\n        CONFIG_DEFAULT,\n        \"yoffset\",\n        {.snum = &config.y_offset},\n        NULL,\n        \"Y-offset relative to location. *DEPRECATED* see rofi-theme manpage \"\n        \"for \"\n        \"new option\",\n    },\n    {\n        xrm_SNumber,\n        CONFIG_DEFAULT,\n        \"xoffset\",\n        {.snum = &config.x_offset},\n        NULL,\n        \"X-offset relative to location. *DEPRECATED* see rofi-theme manpage \"\n        \"for \"\n        \"new option\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"fixed-num-lines\",\n        {.num = &config.fixed_num_lines},\n        NULL,\n        \"Always show number of lines\",\n    },\n\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"show-icons\",\n        {.snum = &config.show_icons},\n        NULL,\n        \"Whether to load and show icons\",\n    },\n\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"preview-cmd\",\n        {.str = &config.preview_cmd},\n        NULL,\n        \"Custom command to generate preview icons\",\n    },\n\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-selection-changed\",\n        {.str = &config.on_selection_changed},\n        NULL,\n        \"Custom command to call when menu selection changes\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-mode-changed\",\n        {.str = &config.on_mode_changed},\n        NULL,\n        \"Custom command to call when menu mode changes\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-entry-accepted\",\n        {.str = &config.on_entry_accepted},\n        NULL,\n        \"Custom command to call when menu entry is accepted\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-menu-canceled\",\n        {.str = &config.on_menu_canceled},\n        NULL,\n        \"Custom command to call when menu is canceled\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-menu-error\",\n        {.str = &config.on_menu_error},\n        NULL,\n        \"Custom command to call when menu finds errors\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"on-screenshot-taken\",\n        {.str = &config.on_screenshot_taken},\n        NULL,\n        \"Custom command to call when menu screenshot is taken\",\n    },\n\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"terminal\",\n        {.str = &config.terminal_emulator},\n        NULL,\n        \"Terminal to use\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"ssh-client\",\n        {.str = &config.ssh_client},\n        NULL,\n        \"Ssh client to use\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"ssh-command\",\n        {.str = &config.ssh_command},\n        NULL,\n        \"Ssh command to execute\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"run-command\",\n        {.str = &config.run_command},\n        NULL,\n        \"Run command to execute\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"run-list-command\",\n        {.str = &config.run_list_command},\n        NULL,\n        \"Command to get extra run targets\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"run-shell-command\",\n        {.str = &config.run_shell_command},\n        NULL,\n        \"Run command to execute that runs in shell\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"window-command\",\n        {.str = &config.window_command},\n        NULL,\n        \"Command to executed when -kb-accept-alt binding is hit on selected \"\n        \"window \",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"window-match-fields\",\n        {.str = &config.window_match_fields},\n        NULL,\n        \"Window fields to match in window mode\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"icon-theme\",\n        {.str = &config.icon_theme},\n        NULL,\n        \"Theme to use to look for icons\",\n    },\n\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"drun-match-fields\",\n        {.str = &config.drun_match_fields},\n        NULL,\n        \"Desktop entry fields to match in drun\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"drun-categories\",\n        {.str = &config.drun_categories},\n        NULL,\n        \"Only show Desktop entry from these categories\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"drun-exclude-categories\",\n        {.str = &config.drun_exclude_categories},\n        NULL,\n        \"Exclude Desktop entries from these categories\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"drun-show-actions\",\n        {.num = &config.drun_show_actions},\n        NULL,\n        \"Desktop entry show actions.\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"drun-display-format\",\n        {.str = &config.drun_display_format},\n        NULL,\n        \"DRUN format string. (Supports: generic,name,comment,exec,categories)\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"drun-url-launcher\",\n        {.str = &config.drun_url_launcher},\n        NULL,\n        \"Command to open a Desktop Entry that is a Link.\",\n    },\n\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"disable-history\",\n        {.num = &config.disable_history},\n        NULL,\n        \"Disable history in run/ssh\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"ignored-prefixes\",\n        {.str = &config.ignored_prefixes},\n        NULL,\n        \"Programs ignored for history\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"sort\",\n        {.num = &config.sort},\n        NULL,\n        \"Sort menu when filtered\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"sorting-method\",\n        {.str = &config.sorting_method},\n        NULL,\n        \"Choose sort strategy: normal (levenshtein) or fzf.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"case-sensitive\",\n        {.num = &config.case_sensitive},\n        NULL,\n        \"Set case-sensitivity\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"case-smart\",\n        {.num = &config.case_smart},\n        NULL,\n        \"Set smartcase like vim (determine case-sensitivity by input)\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"cycle\",\n        {.num = &config.cycle},\n        NULL,\n        \"Cycle through the results list\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"sidebar-mode\",\n        {.num = &config.sidebar_mode},\n        NULL,\n        \"Enable sidebar-mode\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"hover-select\",\n        {.snum = &config.hover_select},\n        NULL,\n        \"Enable hover-select\",\n    },\n    {\n        xrm_SNumber,\n        CONFIG_DEFAULT,\n        \"eh\",\n        {.snum = &config.element_height},\n        NULL,\n        \"Row height (in chars)\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"auto-select\",\n        {.num = &config.auto_select},\n        NULL,\n        \"Enable auto select mode\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"parse-hosts\",\n        {.num = &config.parse_hosts},\n        NULL,\n        \"Parse hosts file for ssh mode\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"parse-known-hosts\",\n        {.num = &config.parse_known_hosts},\n        NULL,\n        \"Parse known_hosts file for ssh mode\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"combi-modi\",\n        {.str = &config.combi_modes},\n        NULL,\n        \"Set the modes to combine in combi mode\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"combi-modes\",\n        {.str = &config.combi_modes},\n        NULL,\n        \"Set the modes to combine in combi mode\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"matching\",\n        {.str = &config.matching},\n        NULL,\n        \"Set the matching algorithm. (normal, regex, glob, fuzzy, prefix)\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"tokenize\",\n        {.num = &config.tokenize},\n        NULL,\n        \"Tokenize input string\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"monitor\",\n        {.str = &config.monitor},\n        NULL,\n        \"\",\n    },\n    /* Alias for dmenu compatibility. */\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"m\",\n        {.str = &config.monitor},\n        NULL,\n        \"Monitor id to show on\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"filter\",\n        {.str = &config.filter},\n        NULL,\n        \"Pre-set filter\",\n    },\n    {\n        xrm_SNumber,\n        CONFIG_DEFAULT,\n        \"dpi\",\n        {.snum = &config.dpi},\n        NULL,\n        \"DPI\",\n    },\n    {\n        xrm_Number,\n        CONFIG_DEFAULT,\n        \"threads\",\n        {.num = &config.threads},\n        NULL,\n        \"Threads to use for string matching\",\n    },\n    {\n        xrm_Number,\n        CONFIG_DEFAULT,\n        \"scroll-method\",\n        {.num = &config.scroll_method},\n        NULL,\n        \"Scrolling method. (0: Page, 1: Centered)\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"window-format\",\n        {.str = &config.window_format},\n        NULL,\n        \"Window Format. w (desktop name), t (title), n (name), r (role), c \"\n        \"(class)\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"click-to-exit\",\n        {.snum = &config.click_to_exit},\n        NULL,\n        \"Click outside the window to exit\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"global-kb\",\n        {.snum = &config.global_kb},\n        NULL,\n        \"Inhibit compositor shortcuts so they can be reused in rofi (wayland)\",\n    },\n    {\n        xrm_String,\n        CONFIG_NO_DISPLAY,\n        \"theme\",\n        {.str = &config.theme},\n        NULL,\n        \"New style theme file\",\n    },\n    {\n        xrm_Number,\n        CONFIG_DEFAULT,\n        \"max-history-size\",\n        {.num = &config.max_history_size},\n        NULL,\n        \"Max history size (WARNING: can cause slowdowns when set too high).\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"combi-hide-mode-prefix\",\n        {.snum = &config.combi_hide_mode_prefix},\n        NULL,\n        \"Hide the prefix mode prefix on the combi view.**deprecated** use \"\n        \"combi-display-format\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"combi-display-format\",\n        {.str = &config.combi_display_format},\n        NULL,\n        \"Combi format string. (Supports: mode, text)\",\n    },\n    {\n        xrm_Char,\n        CONFIG_DEFAULT,\n        \"matching-negate-char\",\n        {.charc = &config.matching_negate_char},\n        NULL,\n        \"Set the character used to negate the matching. ('\\\\0' to disable)\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"cache-dir\",\n        {.str = &config.cache_dir},\n        NULL,\n        \"Directory where history and temporary files are stored.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"window-thumbnail\",\n        {.snum = &config.window_thumbnail},\n        NULL,\n        \"Show window thumbnail (if available) as icon in window switcher.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"drun-use-desktop-cache\",\n        {.snum = &config.drun_use_desktop_cache},\n        NULL,\n        \"DRUN: build and use a cache with desktop file content.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"drun-reload-desktop-cache\",\n        {.snum = &config.drun_reload_desktop_cache},\n        NULL,\n        \"DRUN: If enabled, reload the cache with desktop file content.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"normalize-match\",\n        {.snum = &config.normalize_match},\n        NULL,\n        \"Normalize string when matching (disables match highlighting).\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"steal-focus\",\n        {.snum = &config.steal_focus},\n        NULL,\n        \"Steal focus on launch and restore to window that had it on rofi start \"\n        \"on \"\n        \"close .\",\n    },\n    {\n        xrm_String,\n        CONFIG_DEFAULT,\n        \"application-fallback-icon\",\n        {.str = &(config.application_fallback_icon)},\n        NULL,\n        \"Fallback icon to use when the application icon is not found in \"\n        \"run/drun.\",\n    },\n    {\n        xrm_Number,\n        CONFIG_DEFAULT,\n        \"refilter-timeout-limit\",\n        {.num = &(config.refilter_timeout_limit)},\n        NULL,\n        \"When filtering takes  more then this time (in ms) switch to delayed \"\n        \"filter.\",\n    },\n    {\n        xrm_Boolean,\n        CONFIG_DEFAULT,\n        \"xserver-i300-workaround\",\n        {.snum = &(config.xserver_i300_workaround)},\n        NULL,\n        \"Workaround for XServer issue #300 (issue #611 for rofi.)\",\n    },\n    {xrm_String,\n     CONFIG_DEFAULT,\n     \"completer-mode\",\n     {.str = &(config.completer_mode)},\n     NULL,\n     \"What completer to use for drun/run.\"},\n    {xrm_Boolean,\n     CONFIG_DEFAULT,\n     \"imdkit\",\n     {.snum = &config.enable_imdkit},\n     NULL,\n     \"Whether to enable imdkit\"},\n};\n\n/** Dynamic array of extra options */\nXrmOption *extra_options = NULL;\n/** Number of entries in extra options array */\nunsigned int num_extra_options = 0;\n\n/** This is a big hack, we need to fix this. */\nGList *extra_parsed_options = NULL;\n\nstatic gboolean __config_parser_set_property(XrmOption *option,\n                                             const Property *p, char **error);\n\nvoid config_parser_add_option(XrmOptionType type, const char *key, void **value,\n                              const char *comment) {\n  extra_options =\n      g_realloc(extra_options, (num_extra_options + 1) * sizeof(XrmOption));\n\n  extra_options[num_extra_options].type = type;\n  extra_options[num_extra_options].name = key;\n  extra_options[num_extra_options].value.pointer = value;\n  extra_options[num_extra_options].comment = comment;\n  extra_options[num_extra_options].source = CONFIG_DEFAULT;\n  switch (type) {\n  case xrm_String:\n    extra_options[num_extra_options].mem = ((char *)(*value));\n    break;\n  default:\n    extra_options[num_extra_options].mem = NULL;\n    break;\n  }\n\n  for (GList *iter = g_list_first(extra_parsed_options); iter != NULL;\n       iter = g_list_next(iter)) {\n    if (g_strcmp0(((Property *)(iter->data))->name, key) == 0) {\n      char *error = NULL;\n      g_debug(\"Setting property from backup list: %s\", key);\n      if (__config_parser_set_property(&(extra_options[num_extra_options]),\n                                       (Property *)(iter->data), &error)) {\n        g_debug(\"Failed to set property on custom entry: %s\", key);\n        g_free(error);\n      }\n      num_extra_options++;\n      return;\n    }\n  }\n  num_extra_options++;\n}\n\n/**\n * Parse an option from the commandline vector.\n */\nstatic void config_parse_cmd_option(XrmOption *option) {\n  // Prepend a - to the option name.\n  char *key = g_strdup_printf(\"-%s\", option->name);\n  switch (option->type) {\n  case xrm_Number:\n    if (find_arg_uint(key, option->value.num) == TRUE) {\n      option->source = (option->source & ~3) | CONFIG_CMDLINE;\n    }\n    break;\n  case xrm_SNumber:\n    if (find_arg_int(key, option->value.snum) == TRUE) {\n      option->source = (option->source & ~3) | CONFIG_CMDLINE;\n    }\n    break;\n  case xrm_String:\n    if (find_arg_str(key, option->value.str) == TRUE) {\n      if (option->mem != NULL) {\n        g_free(option->mem);\n        option->mem = NULL;\n      }\n      option->source = (option->source & ~3) | CONFIG_CMDLINE;\n    }\n    break;\n  case xrm_Boolean:\n    if (find_arg(key) >= 0) {\n      *(option->value.num) = TRUE;\n      option->source = (option->source & ~3) | CONFIG_CMDLINE;\n    } else {\n      g_free(key);\n      key = g_strdup_printf(\"-no-%s\", option->name);\n      if (find_arg(key) >= 0) {\n        *(option->value.num) = FALSE;\n        option->source = (option->source & ~3) | CONFIG_CMDLINE;\n      }\n    }\n    break;\n  case xrm_Char:\n    if (find_arg_char(key, option->value.charc) == TRUE) {\n      option->source = (option->source & ~3) | CONFIG_CMDLINE;\n    }\n    break;\n  default:\n    break;\n  }\n  g_free(key);\n}\n\nstatic gboolean config_parser_form_rasi_format(GString *str, char **tokens,\n                                               int count, char *argv,\n                                               gboolean string) {\n  if (strlen(argv) > 4096) {\n    return FALSE;\n  }\n  for (int j = 0; j < (count - 1); j++) {\n    g_string_append_printf(str, \"%s { \", tokens[j]);\n  }\n  if (string) {\n    char *esc = g_strescape(argv, NULL);\n    g_string_append_printf(str, \"%s: \\\"%s\\\";\", tokens[count - 1], esc);\n    g_free(esc);\n  } else {\n    g_string_append_printf(str, \"%s: %s;\", tokens[count - 1], argv);\n  }\n  for (int j = 0; j < (count - 1); j++) {\n    g_string_append(str, \" } \");\n  }\n  return TRUE;\n}\n\nvoid config_parse_cmd_options(void) {\n  for (unsigned int i = 0; i < sizeof(xrmOptions) / sizeof(XrmOption); ++i) {\n    XrmOption *op = &(xrmOptions[i]);\n    config_parse_cmd_option(op);\n  }\n  for (unsigned int i = 0; i < num_extra_options; ++i) {\n    XrmOption *op = &(extra_options[i]);\n    config_parse_cmd_option(op);\n  }\n\n  /** copy of the argc for use in commandline argument parser. */\n  extern int stored_argc;\n  /** copy of the argv pointer for use in the commandline argument parser */\n  extern char **stored_argv;\n  for (int in = 1; in < (stored_argc - 1); in++) {\n    if (stored_argv[in][0] == '-') {\n      if (stored_argv[in + 1][0] == '-') {\n        continue;\n      }\n      /** TODO: This is a hack, and should be fixed in a nicer way. */\n      char **tokens = g_strsplit(stored_argv[in], \"-\", 3);\n      int count = 1;\n      for (int j = 1; tokens && tokens[j]; j++) {\n        count++;\n      }\n      if (count >= 2) {\n        if (g_str_has_prefix(tokens[1], \"theme\")) {\n          g_strfreev(tokens);\n          tokens = g_strsplit(stored_argv[in], \"+\", 0);\n          count = g_strv_length(tokens);\n          if (count > 2) {\n            GString *str = g_string_new(\"\");\n            config_parser_form_rasi_format(str, &(tokens[1]), count - 1,\n                                           stored_argv[in + 1], FALSE);\n            if (rofi_theme_parse_string(str->str) == 1) {\n              /** Failed to parse, try again as string. */\n              g_strfreev(tokens);\n              g_string_free(str, TRUE);\n              return;\n            }\n            g_string_free(str, TRUE);\n          }\n        } else if (g_strcmp0(tokens[1], \"no\") != 0) {\n          GString *str = g_string_new(\"configuration { \");\n          config_parser_form_rasi_format(str, &(tokens[1]), count - 1,\n                                         stored_argv[in + 1], FALSE);\n          g_string_append(str, \"}\");\n          g_debug(\"str: \\\"%s\\\"\\n\", str->str);\n          if (rofi_theme_parse_string(str->str) == 1) {\n            /** Failed to parse, try again as string. */\n            rofi_clear_error_messages();\n            g_string_assign(str, \"configuration { \");\n            config_parser_form_rasi_format(str, &(tokens[1]), count - 1,\n                                           stored_argv[in + 1], TRUE);\n            g_string_append(str, \"}\");\n            g_debug(\"str: \\\"%s\\\"\\n\", str->str);\n            if (rofi_theme_parse_string(str->str) == 1) {\n              /** Failed to parse, try again as string. */\n              rofi_clear_error_messages();\n            }\n          }\n          g_string_free(str, TRUE);\n        }\n        in++;\n      }\n      g_strfreev(tokens);\n    }\n  }\n}\n\nstatic gboolean __config_parser_set_property(XrmOption *option,\n                                             const Property *p, char **error) {\n  if (option->type == xrm_String) {\n    if (p->type != P_STRING && (p->type != P_LIST && p->type != P_INTEGER)) {\n      *error =\n          g_strdup_printf(\"Option: %s needs to be set with a string not a %s.\",\n                          option->name, PropertyTypeName[p->type]);\n      return TRUE;\n    }\n    gchar *value = NULL;\n    if (p->type == P_LIST) {\n      for (GList *iter = p->value.list; iter != NULL;\n           iter = g_list_next(iter)) {\n        Property *p2 = (Property *)iter->data;\n        if (value == NULL) {\n          value = g_strdup((char *)(p2->value.s));\n        } else {\n          char *nv = g_strjoin(\",\", value, (char *)(p2->value.s), NULL);\n          g_free(value);\n          value = nv;\n        }\n      }\n    } else if (p->type == P_INTEGER) {\n      value = g_strdup_printf(\"%d\", p->value.i);\n    } else {\n      value = g_strdup(p->value.s);\n    }\n    if ((option)->mem != NULL) {\n      g_free(option->mem);\n      option->mem = NULL;\n    }\n    *(option->value.str) = value;\n\n    // Memory\n    (option)->mem = *(option->value.str);\n    option->source = (option->source & ~3) | CONFIG_FILE_THEME;\n  } else if (option->type == xrm_Number) {\n    if (p->type != P_INTEGER) {\n      *error =\n          g_strdup_printf(\"Option: %s needs to be set with a number not a %s.\",\n                          option->name, PropertyTypeName[p->type]);\n      return TRUE;\n    }\n    *(option->value.snum) = p->value.i;\n    option->source = (option->source & ~3) | CONFIG_FILE_THEME;\n  } else if (option->type == xrm_SNumber) {\n    if (p->type != P_INTEGER) {\n      *error =\n          g_strdup_printf(\"Option: %s needs to be set with a number not a %s.\",\n                          option->name, PropertyTypeName[p->type]);\n      return TRUE;\n    }\n    *(option->value.num) = (unsigned int)(p->value.i);\n    option->source = (option->source & ~3) | CONFIG_FILE_THEME;\n  } else if (option->type == xrm_Boolean) {\n    if (p->type != P_BOOLEAN) {\n      *error =\n          g_strdup_printf(\"Option: %s needs to be set with a boolean not a %s.\",\n                          option->name, PropertyTypeName[p->type]);\n      return TRUE;\n    }\n    *(option->value.num) = (p->value.b);\n    option->source = (option->source & ~3) | CONFIG_FILE_THEME;\n  } else if (option->type == xrm_Char) {\n\n    if (p->type != P_STRING) {\n      *error =\n          g_strdup_printf(\"Option: %s needs to be set with a string not a %s.\",\n                          option->name, PropertyTypeName[p->type]);\n      return TRUE;\n    }\n    *(option->value.charc) = (p->value.s[0]);\n    option->source = (option->source & ~3) | CONFIG_FILE_THEME;\n  } else {\n    // TODO add type\n    *error = g_strdup_printf(\"Option: %s is not of a supported type: %s.\",\n                             option->name, PropertyTypeName[p->type]);\n    return TRUE;\n  }\n  return FALSE;\n}\n\ngboolean config_parse_set_property(const Property *p, char **error) {\n  if (g_ascii_strcasecmp(p->name, \"theme\") == 0) {\n    if (p->type == P_STRING) {\n      *error = g_strdup_printf(\"The option:\\n<b>\\nconfiguration\\n{\\n\\ttheme: \"\n                               \"\\\"%s\\\";\\n}</b>\\nis deprecated. Please replace \"\n                               \"with: <b>@theme \\\"%s\\\"</b> \"\n                               \"after the configuration block.\",\n                               p->value.s, p->value.s);\n    } else {\n      *error = g_strdup_printf(\"The option:\\n<b>\\nconfiguration\\n{\\n\\ttheme: \"\n                               \"\\\"%s\\\";\\n}</b>\\nis deprecated. Please replace \"\n                               \"with: <b>@theme \\\"%s\\\"</b> \"\n                               \"after the configuration block.\",\n                               \"myTheme\", \"myTheme\");\n    }\n    return TRUE;\n  }\n  for (unsigned int i = 0; i < sizeof(xrmOptions) / sizeof(XrmOption); ++i) {\n    XrmOption *op = &(xrmOptions[i]);\n    if (g_strcmp0(op->name, p->name) == 0) {\n      return __config_parser_set_property(op, p, error);\n    }\n  }\n  for (unsigned int i = 0; i < num_extra_options; ++i) {\n    XrmOption *op = &(extra_options[i]);\n    if (g_strcmp0(op->name, p->name) == 0) {\n      return __config_parser_set_property(op, p, error);\n    }\n  }\n  //*error = g_strdup_printf(\"Option: %s is not found.\", p->name);\n  g_debug(\"Option: %s is not found.\", p->name);\n\n  for (GList *iter = g_list_first(extra_parsed_options); iter != NULL;\n       iter = g_list_next(iter)) {\n    if (g_strcmp0(((Property *)(iter->data))->name, p->name) == 0) {\n      rofi_theme_property_free((Property *)(iter->data));\n      iter->data = (void *)rofi_theme_property_copy(p, NULL);\n      return FALSE;\n    }\n  }\n  g_debug(\"Adding option: %s to backup list.\", p->name);\n  extra_parsed_options =\n      g_list_append(extra_parsed_options, rofi_theme_property_copy(p, NULL));\n\n  return FALSE;\n}\n\nvoid config_xresource_free(void) {\n  for (unsigned int i = 0; i < (sizeof(xrmOptions) / sizeof(*xrmOptions));\n       ++i) {\n    if (xrmOptions[i].mem != NULL) {\n      g_free(xrmOptions[i].mem);\n      xrmOptions[i].mem = NULL;\n    }\n  }\n  for (unsigned int i = 0; i < num_extra_options; ++i) {\n    if (extra_options[i].mem != NULL) {\n      g_free(extra_options[i].mem);\n      extra_options[i].mem = NULL;\n    }\n  }\n  if (extra_options != NULL) {\n    g_free(extra_options);\n  }\n  g_list_free_full(extra_parsed_options,\n                   (GDestroyNotify)rofi_theme_property_free);\n}\n\nstatic void config_parse_dump_config_option(FILE *out, XrmOption *option) {\n  if (option->type == xrm_Char || (option->source & 3) == CONFIG_DEFAULT) {\n    fprintf(out, \"/*\");\n  }\n  fprintf(out, \"\\t%s: \", option->name);\n  switch (option->type) {\n  case xrm_Number:\n    fprintf(out, \"%u\", *(option->value.num));\n    break;\n  case xrm_SNumber:\n    fprintf(out, \"%i\", *(option->value.snum));\n    break;\n  case xrm_String:\n    if ((*(option->value.str)) != NULL) {\n      // TODO should this be escaped?\n      fprintf(out, \"\\\"%s\\\"\", *(option->value.str));\n    }\n    break;\n  case xrm_Boolean:\n    fprintf(out, \"%s\", (*(option->value.num) == TRUE) ? \"true\" : \"false\");\n    break;\n  case xrm_Char:\n    // TODO\n    if (*(option->value.charc) > 32 && *(option->value.charc) < 127) {\n      fprintf(out, \"'%c'\", *(option->value.charc));\n    } else {\n      fprintf(out, \"'\\\\x%02X'\", *(option->value.charc));\n    }\n    fprintf(out, \" /* unsupported */\");\n    break;\n  default:\n    break;\n  }\n\n  fprintf(out, \";\");\n  if (option->type == xrm_Char || (option->source & 3) == CONFIG_DEFAULT) {\n    fprintf(out, \"*/\");\n  }\n  fprintf(out, \"\\n\");\n}\n\nvoid config_parse_dump_config_rasi_format(FILE *out, gboolean changes) {\n  fprintf(out, \"configuration {\\n\");\n\n  unsigned int entries = sizeof(xrmOptions) / sizeof(*xrmOptions);\n  for (unsigned int i = 0; i < entries; ++i) {\n    // Skip duplicates.\n    if ((i + 1) < entries) {\n      if (xrmOptions[i].value.str == xrmOptions[i + 1].value.str) {\n        continue;\n      }\n    }\n    if ((xrmOptions[i].source & CONFIG_NO_DISPLAY) == CONFIG_NO_DISPLAY) {\n      continue;\n    }\n    if (!changes || (xrmOptions[i].source & 3) != CONFIG_DEFAULT) {\n      config_parse_dump_config_option(out, &(xrmOptions[i]));\n    }\n  }\n  for (unsigned int i = 0; i < num_extra_options; i++) {\n    if ((extra_options[i].source & CONFIG_NO_DISPLAY) == CONFIG_NO_DISPLAY) {\n      continue;\n    }\n    if (!changes || (extra_options[i].source & 3) != CONFIG_DEFAULT) {\n\n      config_parse_dump_config_option(out, &(extra_options[i]));\n    }\n  }\n\n  for (unsigned int index = 0; index < rofi_configuration->num_widgets;\n       index++) {\n    rofi_theme_print_index(rofi_configuration->widgets[index], 2);\n  }\n\n  fprintf(out, \"}\\n\");\n\n  if (config.theme != NULL) {\n    fprintf(out, \"@theme \\\"%s\\\"\\r\\n\", config.theme);\n  }\n}\n\nstatic void print_option_string(XrmOption *xo, int is_term) {\n  int l = strlen(xo->name);\n  if (is_term) {\n    printf(\"\\t\" color_bold \"-%s\" color_reset \" [string]%-*c%s\\n\", xo->name,\n           30 - l, ' ', xo->comment);\n    printf(\"\\t\" color_italic \"%s\" color_reset,\n           (*(xo->value.str) == NULL) ? \"(unset)\" : (*(xo->value.str)));\n    printf(\" \" color_green \"(%s)\" color_reset \"\\n\",\n           ConfigSourceStr[xo->source & 3]);\n  } else {\n    printf(\"\\t-%s [string]%-*c%s\\n\", xo->name, 30 - l, ' ', xo->comment);\n    printf(\"\\t\\t%s\",\n           (*(xo->value.str) == NULL) ? \"(unset)\" : (*(xo->value.str)));\n    printf(\" (%s)\\n\", ConfigSourceStr[xo->source & 3]);\n  }\n}\nstatic void print_option_number(XrmOption *xo, int is_term) {\n  int l = strlen(xo->name);\n  if (is_term) {\n    printf(\"\\t\" color_bold \"-%s\" color_reset \" [number]%-*c%s\\n\", xo->name,\n           30 - l, ' ', xo->comment);\n    printf(\"\\t\" color_italic \"%u\" color_reset, *(xo->value.num));\n    printf(\" \" color_green \"(%s)\" color_reset \"\\n\",\n           ConfigSourceStr[xo->source & 3]);\n  } else {\n    printf(\"\\t-%s [number]%-*c%s\\n\", xo->name, 30 - l, ' ', xo->comment);\n    printf(\"\\t\\t%u\", *(xo->value.num));\n    printf(\" (%s)\\n\", ConfigSourceStr[xo->source & 3]);\n  }\n}\nstatic void print_option_snumber(XrmOption *xo, int is_term) {\n  int l = strlen(xo->name);\n  if (is_term) {\n    printf(\"\\t\" color_bold \"-%s\" color_reset \" [number]%-*c%s\\n\", xo->name,\n           30 - l, ' ', xo->comment);\n    printf(\"\\t\" color_italic \"%d\" color_reset, *(xo->value.snum));\n    printf(\" \" color_green \"(%s)\" color_reset \"\\n\",\n           ConfigSourceStr[xo->source & 3]);\n  } else {\n    printf(\"\\t-%s [number]%-*c%s\\n\", xo->name, 30 - l, ' ', xo->comment);\n    printf(\"\\t\\t%d\", *(xo->value.snum));\n    printf(\" (%s)\\n\", ConfigSourceStr[xo->source & 3]);\n  }\n}\nstatic void print_option_char(XrmOption *xo, int is_term) {\n  int l = strlen(xo->name);\n  if (is_term) {\n    printf(\"\\t\" color_bold \"-%s\" color_reset \" [character]%-*c%s\\n\", xo->name,\n           30 - l, ' ', xo->comment);\n    printf(\"\\t\" color_italic \"%c\" color_reset, *(xo->value.charc));\n    printf(\" \" color_green \"(%s)\" color_reset \"\\n\",\n           ConfigSourceStr[xo->source & 3]);\n  } else {\n    printf(\"\\t-%s [character]%-*c%s\\n\", xo->name, 30 - l, ' ', xo->comment);\n    printf(\"\\t\\t%c\", *(xo->value.charc));\n    printf(\" (%s)\\n\", ConfigSourceStr[xo->source & 3]);\n  }\n}\nstatic void print_option_boolean(XrmOption *xo, int is_term) {\n  int l = strlen(xo->name);\n  if (is_term) {\n    printf(\"\\t\" color_bold \"-[no-]%s\" color_reset \" %-*c%s\\n\", xo->name, 33 - l,\n           ' ', xo->comment);\n    printf(\"\\t\" color_italic \"%s\" color_reset,\n           (*(xo->value.snum)) ? \"True\" : \"False\");\n    printf(\" \" color_green \"(%s)\" color_reset \"\\n\",\n           ConfigSourceStr[xo->source & 3]);\n  } else {\n    printf(\"\\t-[no-]%s %-*c%s\\n\", xo->name, 33 - l, ' ', xo->comment);\n    printf(\"\\t\\t%s\", (*(xo->value.snum)) ? \"True\" : \"False\");\n    printf(\" (%s)\\n\", ConfigSourceStr[xo->source & 3]);\n  }\n}\n\nstatic void print_option(XrmOption *xo, int is_term) {\n  if ((xo->source & CONFIG_NO_DISPLAY) == CONFIG_NO_DISPLAY) {\n    return;\n  }\n  switch (xo->type) {\n  case xrm_String:\n    print_option_string(xo, is_term);\n    break;\n  case xrm_Number:\n    print_option_number(xo, is_term);\n    break;\n  case xrm_SNumber:\n    print_option_snumber(xo, is_term);\n    break;\n  case xrm_Boolean:\n    print_option_boolean(xo, is_term);\n    break;\n  case xrm_Char:\n    print_option_char(xo, is_term);\n    break;\n  default:\n    break;\n  }\n}\nvoid print_options(void) {\n  // Check output filedescriptor\n  int is_term = isatty(fileno(stdout));\n  unsigned int entries = sizeof(xrmOptions) / sizeof(*xrmOptions);\n  for (unsigned int i = 0; i < entries; ++i) {\n    if ((i + 1) < entries) {\n      if (xrmOptions[i].value.str == xrmOptions[i + 1].value.str) {\n        continue;\n      }\n    }\n    print_option(&xrmOptions[i], is_term);\n  }\n  for (unsigned int i = 0; i < num_extra_options; i++) {\n    print_option(&extra_options[i], is_term);\n  }\n}\n\nvoid print_help_msg(const char *option, const char *type, const char *text,\n                    const char *def, int isatty) {\n  int l = 37 - strlen(option) - strlen(type);\n  if (isatty) {\n    printf(\"\\t%s%s%s %s %-*c%s\\n\", color_bold, option, color_reset, type, l,\n           ' ', text);\n    if (def != NULL) {\n      printf(\"\\t\\t%s%s%s\\n\", color_italic, def, color_reset);\n    }\n  } else {\n    printf(\"\\t%s %s %-*c%s\\n\", option, type, l, ' ', text);\n    if (def != NULL) {\n      printf(\"\\t\\t%s\\n\", def);\n    }\n  }\n}\n\nstatic char *config_parser_return_display_help_entry(XrmOption *option,\n                                                     size_t l) {\n  int ll = (int)l;\n  switch (option->type) {\n  case xrm_Number:\n    return g_markup_printf_escaped(\n        \"<b%-*s</b> (%u) <span style='italic' size='small'>%s</span>\", ll,\n        option->name, *(option->value.num), option->comment);\n  case xrm_SNumber:\n    return g_markup_printf_escaped(\n        \"<b%-*s</b> (%d) <span style='italic' size='small'>%s</span>\", ll,\n        option->name, *(option->value.snum), option->comment);\n  case xrm_String:\n    return g_markup_printf_escaped(\n        \"<b>%-*s</b> (%s) <span style='italic' size='small'>%s</span>\", ll,\n        option->name,\n        (*(option->value.str) != NULL) ? *(option->value.str) : \"null\",\n        option->comment);\n  case xrm_Boolean:\n    return g_markup_printf_escaped(\n        \"<b>%-*s</b> (%s) <span style='italic' size='small'>%s</span>\", ll,\n        option->name, (*(option->value.num) == TRUE) ? \"true\" : \"false\",\n        option->comment);\n  case xrm_Char:\n    if (*(option->value.charc) > 32 && *(option->value.charc) < 127) {\n      return g_markup_printf_escaped(\n          \"<b>%-*s</b> (%c) <span style='italic' size='small'>%s</span>\", ll,\n          option->name, *(option->value.charc), option->comment);\n    } else {\n      return g_markup_printf_escaped(\n          \"<b%-*s</b> (\\\\x%02X) <span style='italic' size='small'>%s</span>\",\n          ll, option->name, *(option->value.charc), option->comment);\n    }\n  default:\n    break;\n  }\n\n  return g_strdup(\"failed\");\n}\n\nchar **config_parser_return_display_help(unsigned int *length) {\n  unsigned int entries = sizeof(xrmOptions) / sizeof(*xrmOptions);\n  char **retv = NULL;\n  /**\n   * Get length of name\n   */\n  size_t max_length = 0;\n  for (unsigned int i = 0; i < entries; ++i) {\n    size_t l = strlen(xrmOptions[i].name);\n    max_length = MAX(max_length, l);\n  }\n  for (unsigned int i = 0; i < num_extra_options; i++) {\n    size_t l = strlen(extra_options[i].name);\n    max_length = MAX(max_length, l);\n  }\n  /**\n   * Generate entries\n   */\n  for (unsigned int i = 0; i < entries; ++i) {\n    if ((i + 1) < entries) {\n      if (xrmOptions[i].value.str == xrmOptions[i + 1].value.str) {\n        continue;\n      }\n    }\n    if (strncmp(xrmOptions[i].name, \"kb\", 2) != 0 &&\n        strncmp(xrmOptions[i].name, \"ml\", 2) != 0 &&\n        strncmp(xrmOptions[i].name, \"me\", 2) != 0) {\n      continue;\n    }\n\n    retv = g_realloc(retv, ((*length) + 2) * sizeof(char *));\n\n    retv[(*length)] =\n        config_parser_return_display_help_entry(&xrmOptions[i], max_length);\n    (*length)++;\n  }\n  for (unsigned int i = 0; i < num_extra_options; i++) {\n    if (strncmp(extra_options[i].name, \"kb\", 2) != 0 &&\n        strncmp(extra_options[i].name, \"ml\", 2) != 0 &&\n        strncmp(extra_options[i].name, \"me\", 2) != 0) {\n      continue;\n    }\n    retv = g_realloc(retv, ((*length) + 2) * sizeof(char *));\n    retv[(*length)] =\n        config_parser_return_display_help_entry(&extra_options[i], max_length);\n    (*length)++;\n  }\n  if ((*length) > 0) {\n    retv[(*length)] = NULL;\n  }\n  return retv;\n}\n"
  },
  {
    "path": "test/box-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"helper.h\"\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"xrmoptions.h\"\n#include <assert.h>\n#include <glib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <theme.h>\n#include <unistd.h>\n#include <widgets/box.h>\n#include <widgets/widget-internal.h>\n#include <widgets/widget.h>\nunsigned int test = 0;\nint rofi_is_in_dmenu_mode = 0;\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %3u passed (%s)\\n\", ++test, #a);                              \\\n  }\n\n#define TASSERTE(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %u passed (%s == %s) (%d == %d)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %u failed (%s == %s) (%d != %d)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\n\n#define TASSERTW(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %u passed (%s == %s) (%p == %p)\\n\", ++test, #a, #b,         \\\n             (void *)a, (void *)b);                                            \\\n    } else {                                                                   \\\n      printf(\"Test %u failed (%s == %s) (%p != %p)\\n\", ++test, #a, #b,         \\\n             (void *)a, (void *)b);                                            \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\nThemeWidget *rofi_configuration = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\ngboolean config_parse_set_property(G_GNUC_UNUSED const Property *p,\n                                   G_GNUC_UNUSED char **error) {\n  return FALSE;\n}\nchar *rofi_expand_path(G_GNUC_UNUSED const char *path) { return NULL; }\n\nchar *helper_get_theme_path(const char *file, G_GNUC_UNUSED const char **ext,\n                            G_GNUC_UNUSED const char *parent_file) {\n  return g_strdup(file);\n}\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\ndouble textbox_get_estimated_char_height(void);\ndouble textbox_get_estimated_char_height(void) { return 16; }\ndouble textbox_get_estimated_ch(void);\ndouble textbox_get_estimated_ch(void) { return 8; }\nvoid rofi_view_get_current_monitor(G_GNUC_UNUSED int *width,\n                                   G_GNUC_UNUSED int *height) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  {\n    box *b = box_create(NULL, \"box\", ROFI_ORIENTATION_HORIZONTAL);\n    // box_set_padding ( b, 5 );\n    widget_resize(WIDGET(b), 100, 20);\n\n    widget *wid1 = g_malloc0(sizeof(widget));\n    wid1->parent = WIDGET(b);\n    box_add(b, WIDGET(wid1), TRUE);\n    // Widget not enabled.  no width allocated.\n    TASSERTE(wid1->h, 0);\n    TASSERTE(wid1->w, 0);\n    widget_enable(WIDGET(wid1));\n    widget_update(WIDGET(b));\n    // Widget enabled.  so width allocated.\n    TASSERTE(wid1->h, 20);\n    TASSERTE(wid1->w, 100);\n    widget *wid2 = g_malloc0(sizeof(widget));\n    wid2->parent = WIDGET(b);\n    widget_enable(WIDGET(wid2));\n    box_add(b, WIDGET(wid2), TRUE);\n    TASSERTE(wid1->h, 20);\n    TASSERTE(wid1->w, 49);\n    TASSERTE(wid2->h, 20);\n    TASSERTE(wid2->w, 49);\n\n    widget *wid3 = g_malloc0(sizeof(widget));\n    wid3->parent = WIDGET(b);\n    widget_enable(WIDGET(wid3));\n    box_add(b, WIDGET(wid3), FALSE);\n    TASSERTE(wid1->h, 20);\n    TASSERTE(wid1->w, 48);\n    TASSERTE(wid2->h, 20);\n    TASSERTE(wid2->w, 48);\n\n    widget_resize(WIDGET(wid3), 20, 10);\n    // TODO should this happen automagically?\n    widget_update(WIDGET(b));\n    TASSERTE(wid1->h, 20);\n    TASSERTE(wid1->w, 38);\n    TASSERTE(wid2->h, 20);\n    TASSERTE(wid2->w, 38);\n    TASSERTE(wid3->h, 20);\n    TASSERTE(wid3->w, 20);\n\n    widget_resize(WIDGET(b), 200, 20);\n    TASSERTE(wid1->h, 20);\n    TASSERTE(wid1->w, 88);\n    TASSERTE(wid2->h, 20);\n    TASSERTE(wid2->w, 88);\n    TASSERTE(wid3->h, 20);\n    TASSERTE(wid3->w, 20);\n    //        TASSERTE ( box_get_fixed_pixels ( b ) , 24 );\n\n    widget *wid4 = g_malloc0(sizeof(widget));\n    wid4->parent = WIDGET(b);\n    widget_enable(WIDGET(wid4));\n    widget_resize(WIDGET(wid4), 20, 20);\n    box_add(b, WIDGET(wid4), FALSE);\n    TASSERTE(wid4->x, 200 - 20);\n    widget *wid5 = g_malloc0(sizeof(widget));\n    wid5->parent = WIDGET(b);\n    widget_enable(WIDGET(wid5));\n    widget_resize(WIDGET(wid5), 20, 20);\n    box_add(b, WIDGET(wid5), TRUE);\n    TASSERTE(wid5->x, 149);\n    widget_free(WIDGET(b));\n  }\n  {\n    box *b = box_create(NULL, \"box\", ROFI_ORIENTATION_VERTICAL);\n    widget_resize(WIDGET(b), 20, 100);\n    // box_set_padding ( b, 5 );\n\n    widget *wid1 = g_malloc0(sizeof(widget));\n    wid1->parent = WIDGET(b);\n    box_add(b, WIDGET(wid1), TRUE);\n    // Widget not enabled.  no width allocated.\n    TASSERTE(wid1->h, 0);\n    TASSERTE(wid1->w, 0);\n    widget_enable(WIDGET(wid1));\n    widget_update(WIDGET(b));\n    // Widget enabled.  so width allocated.\n    TASSERTE(wid1->h, 100);\n    TASSERTE(wid1->w, 20);\n    widget *wid2 = g_malloc0(sizeof(widget));\n    wid2->parent = WIDGET(b);\n    widget_enable(WIDGET(wid2));\n    box_add(b, WIDGET(wid2), TRUE);\n    TASSERTE(wid1->w, 20);\n    TASSERTE(wid1->h, 49);\n    TASSERTE(wid2->w, 20);\n    TASSERTE(wid2->h, 49);\n\n    widget *wid3 = g_malloc0(sizeof(widget));\n    wid3->parent = WIDGET(b);\n    widget_enable(WIDGET(wid3));\n    box_add(b, WIDGET(wid3), FALSE);\n    TASSERTE(wid1->w, 20);\n    TASSERTE(wid1->h, 48);\n    TASSERTE(wid2->w, 20);\n    TASSERTE(wid2->h, 48);\n\n    widget_resize(WIDGET(wid3), 10, 20);\n    // TODO should this happen automagically?\n    widget_update(WIDGET(b));\n    TASSERTE(wid1->w, 20);\n    TASSERTE(wid1->h, 38);\n    TASSERTE(wid2->w, 20);\n    TASSERTE(wid2->h, 38);\n    TASSERTE(wid3->w, 20);\n    TASSERTE(wid3->h, 20);\n\n    widget_resize(WIDGET(b), 20, 200);\n    TASSERTE(wid1->w, 20);\n    TASSERTE(wid1->h, 88);\n    TASSERTE(wid2->w, 20);\n    TASSERTE(wid2->h, 88);\n    TASSERTE(wid3->w, 20);\n    TASSERTE(wid3->h, 20);\n    //        TASSERTE ( box_get_fixed_pixels ( b ) , 4 );\n    widget *wid4 = g_malloc0(sizeof(widget));\n    wid4->parent = WIDGET(b);\n    widget_enable(WIDGET(wid4));\n    widget_resize(WIDGET(wid4), 20, 20);\n    box_add(b, WIDGET(wid4), FALSE);\n    TASSERTE(wid4->y, 180);\n    widget *wid5 = g_malloc0(sizeof(widget));\n    wid5->parent = WIDGET(b);\n    widget_enable(WIDGET(wid5));\n    widget_resize(WIDGET(wid5), 20, 20);\n    box_add(b, WIDGET(wid5), TRUE);\n    TASSERTE(wid5->y, 149);\n    widget_free(WIDGET(b));\n  }\n  {\n    box *b = box_create(NULL, \"box\", ROFI_ORIENTATION_VERTICAL);\n    widget_resize(WIDGET(b), 20, 90);\n    // box_set_padding ( b, 5 );\n    widget *wid1 = g_malloc0(sizeof(widget));\n    wid1->parent = WIDGET(b);\n    wid1->type = 1;\n    widget_enable(wid1);\n    box_add(b, WIDGET(wid1), TRUE);\n    widget *wid2 = g_malloc0(sizeof(widget));\n    wid2->parent = WIDGET(b);\n    wid2->type = 1;\n    widget_enable(wid2);\n    box_add(b, WIDGET(wid2), TRUE);\n    widget *wid3 = g_malloc0(sizeof(widget));\n    wid3->parent = WIDGET(b);\n    wid3->type = 2;\n    widget_enable(wid3);\n    box_add(b, WIDGET(wid3), TRUE);\n\n    gint x = 10;\n    gint y = 50;\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 1, x, y), WIDGET(wid2));\n\n    y = 30;\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 1, x, y), WIDGET(wid2));\n    y = 27;\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 1, x, y), WIDGET(wid1));\n    widget_disable(wid2);\n    y = 40;\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 1, x, y), WIDGET(wid1));\n    widget_disable(wid1);\n    widget_enable(wid2);\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 1, x, y), WIDGET(wid2));\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 2, x, y), NULL);\n    y = 55;\n    TASSERTW(widget_find_mouse_target(WIDGET(b), 2, x, y), WIDGET(wid3));\n    widget_free(WIDGET(b));\n  }\n}\n"
  },
  {
    "path": "test/helper-config-cmdline-parser.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"config.h\"\n\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"widgets/textbox.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\nstatic int test = 0;\n\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %i passed (%s)\\n\", ++test, #a);                               \\\n  }\n#define TASSERTE(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %i passed (%s == %s) (%u == %u)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %i failed (%s == %s) (%u != %u)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\n#include \"theme.h\"\nThemeWidget *rofi_theme = NULL;\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\n\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) {\n  return FALSE;\n}\n\ndouble textbox_get_estimated_char_height(void) { return 12.0; }\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  *width = 1920;\n  *height = 1080;\n}\ndouble textbox_get_estimated_ch(void) { return 9.0; }\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n  char **list = NULL;\n  int llength = 0;\n  char *test_str = \"{host} {terminal} -e bash -c \\\"{ssh-client} {host}; echo \"\n                   \"'{terminal} {host}'\\\" -i -3 -u 4\";\n  helper_parse_setup(test_str, &list, &llength, \"{host}\", \"chuck\", \"{terminal}\",\n                     \"x-terminal-emulator\", NULL);\n\n  TASSERT(llength == 10);\n  TASSERT(strcmp(list[0], \"chuck\") == 0);\n  TASSERT(strcmp(list[1], \"x-terminal-emulator\") == 0);\n  TASSERT(strcmp(list[2], \"-e\") == 0);\n  TASSERT(strcmp(list[3], \"bash\") == 0);\n  TASSERT(strcmp(list[4], \"-c\") == 0);\n  TASSERT(strcmp(list[5], \"ssh chuck; echo 'x-terminal-emulator chuck'\") == 0);\n  TASSERT(strcmp(list[6], \"-i\") == 0);\n  TASSERT(strcmp(list[7], \"-3\") == 0);\n  TASSERT(strcmp(list[8], \"-u\") == 0);\n  TASSERT(strcmp(list[9], \"4\") == 0);\n\n  cmd_set_arguments(llength, list);\n  TASSERT(find_arg(\"-e\") == 2);\n  TASSERT(find_arg(\"-x\") == -1);\n  char *str;\n  TASSERT(find_arg_str(\"-e\", &str) == TRUE);\n  TASSERT(str == list[3]);\n  TASSERT(find_arg_str(\"-x\", &str) == FALSE);\n  // Should be unmodified.\n  TASSERT(str == list[3]);\n\n  unsigned int u = 1234;\n  int d = -1234;\n  TASSERT(find_arg_uint(\"-x\", &u) == FALSE);\n  TASSERT(u == 1234);\n  TASSERT(find_arg_int(\"-x\", &d) == FALSE);\n  TASSERT(d == -1234);\n  TASSERT(find_arg_uint(\"-u\", &u) == TRUE);\n  TASSERT(u == 4);\n  TASSERT(find_arg_uint(\"-i\", &u) == TRUE);\n  TASSERT(u == 4294967293);\n  TASSERT(find_arg_int(\"-i\", &d) == TRUE);\n  TASSERT(d == -3);\n\n  g_strfreev(list);\n}\n"
  },
  {
    "path": "test/helper-expand.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n#include \"config.h\"\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"theme.h\"\n#include \"widgets/textbox.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\nstatic int test = 0;\n\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %i passed (%s)\\n\", ++test, #a);                               \\\n  }\n#define TASSERTE(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %i passed (%s == %s) (%u == %u)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %i failed (%s == %s) (%u != %u)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\nThemeWidget *rofi_theme = NULL;\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ndouble textbox_get_estimated_char_height(void) { return 12.0; }\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  *width = 1920;\n  *height = 1080;\n}\ndouble textbox_get_estimated_ch(void) { return 9.0; }\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) { return 0; }\n\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\n\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(int argc, char **argv) {\n  cmd_set_arguments(argc, argv);\n\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n\n  /**\n   * Test some path functions. Not easy as not sure what is right output on\n   * travis.\n   */\n  // Test if root is preserved.\n  char *str = rofi_expand_path(\"/\");\n  TASSERT(strcmp(str, \"/\") == 0);\n  g_free(str);\n  // Test is relative path is preserved.\n  str = rofi_expand_path(\"../AUTHORS\");\n  TASSERT(strcmp(str, \"../AUTHORS\") == 0);\n  g_free(str);\n  // Test another one.\n  str = rofi_expand_path(\"/bin/false\");\n  TASSERT(strcmp(str, \"/bin/false\") == 0);\n  g_free(str);\n  // See if user paths get expanded in full path.\n  str = rofi_expand_path(\"~/\");\n  const char *hd = g_get_home_dir();\n  TASSERT(strcmp(str, hd) == 0);\n  g_free(str);\n  str = rofi_expand_path(\"~root/\");\n  TASSERT(str[0] == '/');\n  g_free(str);\n}\n"
  },
  {
    "path": "test/helper-pidfile.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"widgets/textbox.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\nstatic int test = 0;\n\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %i passed (%s)\\n\", ++test, #a);                               \\\n  }\n#include \"theme.h\"\nThemeWidget *rofi_theme = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\n\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) {\n  return FALSE;\n}\ndouble textbox_get_estimated_char_height(void) { return 12.0; }\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  *width = 1920;\n  *height = 1080;\n}\ndouble textbox_get_estimated_ch(void) { return 9.0; }\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n  // Pid test.\n  // Tests basic functionality of writing it, locking, seeing if I can write\n  // same again And close/reopen it again.\n  {\n    const char *tmpd = g_get_tmp_dir();\n    char *path = g_build_filename(tmpd, \"rofi-pid.pid\", NULL);\n    TASSERT(create_pid_file(NULL, FALSE) == -1);\n    int fd = create_pid_file(path, FALSE);\n    TASSERT(fd >= 0);\n    int fd2 = create_pid_file(path, FALSE);\n    TASSERT(fd2 < 0);\n\n    remove_pid_file(fd);\n    fd = create_pid_file(path, FALSE);\n    TASSERT(fd >= 0);\n    remove_pid_file(fd);\n    free(path);\n  }\n}\n"
  },
  {
    "path": "test/helper-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"config.h\"\n\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"theme.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\nstatic int test = 0;\n\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %i passed (%s)\\n\", ++test, #a);                               \\\n  }\n#define TASSERTE(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %i passed (%s == %s) (%u == %u)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %i failed (%s == %s) (%u != %u)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\n#define TASSERTL(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %i passed (%s == %s) (%d == %d)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %i failed (%s == %s) (%d != %d)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\n\n#include \"widgets/textbox.h\"\n\nThemeWidget *rofi_theme = NULL;\n\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) {\n  return FALSE;\n}\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ndouble textbox_get_estimated_char_height(void) { return 12.0; }\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  *width = 1920;\n  *height = 1080;\n}\ndouble textbox_get_estimated_ch(void) { return 9.0; }\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\n\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(int argc, char **argv) {\n  cmd_set_arguments(argc, argv);\n\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n\n  /**\n   * Char function\n   */\n\n  TASSERT(helper_parse_char(\"\\\\n\") == '\\n');\n  TASSERT(helper_parse_char(\"\\\\a\") == '\\a');\n  TASSERT(helper_parse_char(\"\\\\b\") == '\\b');\n  TASSERT(helper_parse_char(\"\\\\t\") == '\\t');\n  TASSERT(helper_parse_char(\"\\\\v\") == '\\v');\n  TASSERT(helper_parse_char(\"\\\\f\") == '\\f');\n  TASSERT(helper_parse_char(\"\\\\r\") == '\\r');\n  TASSERT(helper_parse_char(\"\\\\\\\\\") == '\\\\');\n  TASSERT(helper_parse_char(\"\\\\0\") == 0);\n  TASSERT(helper_parse_char(\"\\\\x77\") == 'w');\n  TASSERT(helper_parse_char(\"\\\\x0A\") == '\\n');\n\n  /**\n   * tokenize\n   */\n\n  TASSERT(levenshtein(\"aap\", g_utf8_strlen(\"aap\", -1), \"aap\",\n                      g_utf8_strlen(\"aap\", -1), 0) == 0);\n  TASSERT(levenshtein(\"aap\", g_utf8_strlen(\"aap\", -1), \"aap \",\n                      g_utf8_strlen(\"aap \", -1), 0) == 1);\n  TASSERT(levenshtein(\"aap \", g_utf8_strlen(\"aap \", -1), \"aap\",\n                      g_utf8_strlen(\"aap\", -1), 0) == 1);\n  TASSERTE(levenshtein(\"aap\", g_utf8_strlen(\"aap\", -1), \"aap noot\",\n                       g_utf8_strlen(\"aap noot\", -1), 0),\n           5u);\n  TASSERTE(levenshtein(\"aap\", g_utf8_strlen(\"aap\", -1), \"noot aap\",\n                       g_utf8_strlen(\"noot aap\", -1), 0),\n           5u);\n  TASSERTE(levenshtein(\"aap\", g_utf8_strlen(\"aap\", -1), \"noot aap mies\",\n                       g_utf8_strlen(\"noot aap mies\", -1), 0),\n           10u);\n  TASSERTE(levenshtein(\"noot aap mies\", g_utf8_strlen(\"noot aap mies\", -1),\n                       \"aap\", g_utf8_strlen(\"aap\", -1), 0),\n           10u);\n  TASSERTE(levenshtein(\"otp\", g_utf8_strlen(\"otp\", -1), \"noot aap\",\n                       g_utf8_strlen(\"noot aap\", -1), 0),\n           5u);\n  /**\n   * Quick converision check.\n   */\n  {\n    char *str = rofi_latin_to_utf8_strdup(\"\\xA1\\xB5\", 2);\n    TASSERT(g_utf8_collate(str, \"¡µ\") == 0);\n    g_free(str);\n  }\n\n  {\n    char *str = rofi_force_utf8(\"Valid utf8\", 10);\n    TASSERT(g_utf8_collate(str, \"Valid utf8\") == 0);\n    g_free(str);\n    char in[] = \"Valid utf8 until \\xc3\\x28 we continue here\";\n    TASSERT(g_utf8_validate(in, -1, NULL) == FALSE);\n    str = rofi_force_utf8(in, strlen(in));\n    TASSERT(g_utf8_validate(str, -1, NULL) == TRUE);\n    TASSERT(g_utf8_collate(str, \"Valid utf8 until �( we continue here\") == 0);\n    g_free(str);\n  }\n  {\n    TASSERT(utf8_strncmp(\"aapno\", \"aap€\", 3) == 0);\n    TASSERT(utf8_strncmp(\"aapno\", \"aap€\", 4) != 0);\n    TASSERT(utf8_strncmp(\"aapno\", \"a\", 4) != 0);\n    TASSERT(utf8_strncmp(\"a\", \"aap€\", 4) != 0);\n    //        char in[] = \"Valid utf8 until \\xc3\\x28 we continue here\";\n    //        TASSERT ( utf8_strncmp ( in, \"Valid\", 3 ) == 0);\n  }\n  {\n    TASSERTL(\n        rofi_scorer_fuzzy_evaluate(\"aap noot mies\", 12, \"aap noot mies\", 12, 0),\n        -605);\n    TASSERTL(rofi_scorer_fuzzy_evaluate(\"anm\", 3, \"aap noot mies\", 12, 0),\n             -155);\n    TASSERTL(rofi_scorer_fuzzy_evaluate(\"blu\", 3, \"aap noot mies\", 12, 0),\n             1073741824);\n    TASSERTL(rofi_scorer_fuzzy_evaluate(\"Anm\", 3, \"aap noot mies\", 12, 1),\n             1073741754);\n    TASSERTL(rofi_scorer_fuzzy_evaluate(\"Anm\", 3, \"aap noot mies\", 12, 0),\n             -155);\n    TASSERTL(rofi_scorer_fuzzy_evaluate(\"aap noot mies\", 12, \"Anm\", 3, 0),\n             1073741824);\n  }\n\n  /**\n   * Case sensitivity\n   */\n  {\n    int case_smart = config.case_smart;\n    int case_sensitive = config.case_sensitive;\n    {\n      config.case_smart = FALSE;\n      config.case_sensitive = FALSE;\n      TASSERT(parse_case_sensitivity(\"all lower case 你好\") == 0);\n      TASSERT(parse_case_sensitivity(\"not All lowEr Case 你好\") == 0);\n      config.case_sensitive = TRUE;\n      TASSERT(parse_case_sensitivity(\"all lower case 你好\") == 1);\n      TASSERT(parse_case_sensitivity(\"not All lowEr Case 你好\") == 1);\n    }\n    {\n      config.case_smart = TRUE;\n      config.case_sensitive = TRUE;\n      TASSERT(parse_case_sensitivity(\"all lower case\") == 0);\n      TASSERT(parse_case_sensitivity(\"AAAAAAAAAAAA\") == 1);\n      config.case_sensitive = FALSE;\n      TASSERT(parse_case_sensitivity(\"all lower case 你好\") == 0);\n      TASSERT(parse_case_sensitivity(\"not All lowEr Case 你好\") == 1);\n    }\n    config.case_smart = case_smart;\n    config.case_sensitive = case_sensitive;\n  }\n\n  char *a;\n  a = helper_string_replace_if_exists(\n      \"{terminal} [-t {title} blub ]-e {cmd}\", \"{cmd}\", \"aap\", \"{title}\",\n      \"some title\", \"{terminal}\", \"rofi-sensible-terminal\", NULL);\n  printf(\"%s\\n\", a);\n  TASSERT(g_utf8_collate(\n              a, \"rofi-sensible-terminal -t some title blub -e aap\") == 0);\n  g_free(a);\n  a = helper_string_replace_if_exists(\"{terminal} [-t {title} blub ]-e {cmd}\",\n                                      \"{cmd}\", \"aap\", \"{terminal}\",\n                                      \"rofi-sensible-terminal\", NULL);\n  printf(\"%s\\n\", a);\n  TASSERT(g_utf8_collate(a, \"rofi-sensible-terminal -e aap\") == 0);\n  g_free(a);\n  a = helper_string_replace_if_exists(\n      \"{name} [<span weight='light' size='small'><i>({category})</i></span>]\",\n      \"{name}\", \"Librecad\", \"{category}\", \"Desktop app\", \"{terminal}\",\n      \"rofi-sensible-terminal\", NULL);\n  printf(\"%s\\n\", a);\n  TASSERT(g_utf8_collate(a, \"Librecad <span weight='light' \"\n                            \"size='small'><i>(Desktop app)</i></span>\") == 0);\n  g_free(a);\n  a = helper_string_replace_if_exists(\n      \"{name}[ <span weight='light' size='small'><i>({category})</i></span>]\",\n      \"{name}\", \"Librecad\", \"{terminal}\", \"rofi-sensible-terminal\", NULL);\n  TASSERT(g_utf8_collate(a, \"Librecad\") == 0);\n  g_free(a);\n  a = helper_string_replace_if_exists(\n      \"{terminal} [{title} blub ]-e {cmd}\", \"{cmd}\", \"aap\", \"{title}\",\n      \"some title\", \"{terminal}\", \"rofi-sensible-terminal\", NULL);\n  printf(\"%s\\n\", a);\n  TASSERT(g_utf8_collate(a, \"rofi-sensible-terminal some title blub -e aap\") ==\n          0);\n  g_free(a);\n  a = helper_string_replace_if_exists(\n      \"{terminal} [{title} blub ]-e {cmd}\", \"{cmd}\", \"aap\", \"{title}\", NULL,\n      \"{terminal}\", \"rofi-sensible-terminal\", NULL);\n  printf(\"%s\\n\", a);\n  TASSERT(g_utf8_collate(a, \"rofi-sensible-terminal -e aap\") == 0);\n  g_free(a);\n}\n"
  },
  {
    "path": "test/helper-tokenize.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi-types.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"theme.h\"\n#include \"widgets/textbox.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\nThemeWidget *rofi_theme = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) {\n  return FALSE;\n}\n\ndouble textbox_get_estimated_char_height(void) { return 12.0; }\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  *width = 1920;\n  *height = 1080;\n}\ndouble textbox_get_estimated_ch(void) { return 9.0; }\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\nSTART_TEST(test_tokenizer_free) { helper_tokenize_free(NULL); }\nEND_TEST\nSTART_TEST(test_tokenizer_match_normal_single_ci) {\n  config.matching_method = MM_NORMAL;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", FALSE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), TRUE);\n\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_normal_single_cs) {\n  config.matching_method = MM_NORMAL;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", TRUE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), FALSE);\n\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_normal_multiple_ci) {\n  config.matching_method = MM_NORMAL;\n  rofi_int_matcher **tokens = helper_tokenize(\"no ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_normal_single_ci_negate) {\n  config.matching_method = MM_NORMAL;\n  rofi_int_matcher **tokens = helper_tokenize(\"-noot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_normal_multiple_ci_negate) {\n  config.matching_method = MM_NORMAL;\n  rofi_int_matcher **tokens = helper_tokenize(\"-noot aap\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_single_ci) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", FALSE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), TRUE);\n\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_single_cs) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", TRUE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_multiple_ci) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"no ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_single_ci_question) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"n?ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_single_ci_star) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"n*ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_glob_multiple_ci_star) {\n  config.matching_method = MM_GLOB;\n  rofi_int_matcher **tokens = helper_tokenize(\"n* ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"ot nap mies\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_fuzzy_single_ci) {\n  config.matching_method = MM_FUZZY;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", FALSE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), TRUE);\n\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_fuzzy_single_cs) {\n  config.matching_method = MM_FUZZY;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", TRUE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_fuzzy_multiple_ci) {\n  config.matching_method = MM_FUZZY;\n  rofi_int_matcher **tokens = helper_tokenize(\"no ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n\n  tokens = helper_tokenize(\"n ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_fuzzy_single_ci_split) {\n  config.matching_method = MM_FUZZY;\n  rofi_int_matcher **tokens = helper_tokenize(\"ont\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap nmiest\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_fuzzy_multiple_ci_split) {\n  config.matching_method = MM_FUZZY;\n  rofi_int_matcher **tokens = helper_tokenize(\"o n t\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"ot nap mies\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_single_ci) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", FALSE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), TRUE);\n\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_single_cs) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"noot\", TRUE);\n\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap Noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"Nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noOTap mies\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_multiple_ci) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"no ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_single_ci_dq) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"n.?ot\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_single_two_char) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"n[oa]{2}t\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noat miesot\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noaat miesot\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nSTART_TEST(test_tokenizer_match_regex_single_two_word_till_end) {\n  config.matching_method = MM_REGEX;\n  rofi_int_matcher **tokens = helper_tokenize(\"^(aap|noap)\\\\sMie.*\", FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap noot mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"aap mies\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nooaap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"nootap mies\"), FALSE);\n  ck_assert_int_eq(helper_token_match(tokens, \"noap miesot\"), TRUE);\n  ck_assert_int_eq(helper_token_match(tokens, \"ot nap mies\"), FALSE);\n  helper_tokenize_free(tokens);\n}\nEND_TEST\n\nstatic Suite *helper_tokenizer_suite(void) {\n  Suite *s;\n\n  s = suite_create(\"Tokenizer\");\n\n  /* Core test case */\n  {\n    TCase *tc_core;\n    tc_core = tcase_create(\"Core\");\n    tcase_add_test(tc_core, test_tokenizer_free);\n    suite_add_tcase(s, tc_core);\n  }\n  {\n    TCase *tc_normal = tcase_create(\"Normal\");\n    tcase_add_test(tc_normal, test_tokenizer_match_normal_single_ci);\n    tcase_add_test(tc_normal, test_tokenizer_match_normal_single_cs);\n    tcase_add_test(tc_normal, test_tokenizer_match_normal_multiple_ci);\n    tcase_add_test(tc_normal, test_tokenizer_match_normal_single_ci_negate);\n    tcase_add_test(tc_normal, test_tokenizer_match_normal_multiple_ci_negate);\n    suite_add_tcase(s, tc_normal);\n  }\n  {\n    TCase *tc_glob = tcase_create(\"Glob\");\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_single_ci);\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_single_cs);\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_multiple_ci);\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_single_ci_question);\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_single_ci_star);\n    tcase_add_test(tc_glob, test_tokenizer_match_glob_multiple_ci_star);\n    suite_add_tcase(s, tc_glob);\n  }\n  {\n    TCase *tc_fuzzy = tcase_create(\"Fuzzy\");\n    tcase_add_test(tc_fuzzy, test_tokenizer_match_fuzzy_single_ci);\n    tcase_add_test(tc_fuzzy, test_tokenizer_match_fuzzy_single_cs);\n    tcase_add_test(tc_fuzzy, test_tokenizer_match_fuzzy_single_ci_split);\n    tcase_add_test(tc_fuzzy, test_tokenizer_match_fuzzy_multiple_ci);\n    tcase_add_test(tc_fuzzy, test_tokenizer_match_fuzzy_multiple_ci_split);\n    suite_add_tcase(s, tc_fuzzy);\n  }\n  {\n    TCase *tc_regex = tcase_create(\"Regex\");\n    tcase_add_test(tc_regex, test_tokenizer_match_regex_single_ci);\n    tcase_add_test(tc_regex, test_tokenizer_match_regex_single_cs);\n    tcase_add_test(tc_regex, test_tokenizer_match_regex_single_ci_dq);\n    tcase_add_test(tc_regex, test_tokenizer_match_regex_single_two_char);\n    tcase_add_test(tc_regex,\n                   test_tokenizer_match_regex_single_two_word_till_end);\n    tcase_add_test(tc_regex, test_tokenizer_match_regex_multiple_ci);\n    suite_add_tcase(s, tc_regex);\n  }\n\n  return s;\n}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  if (setlocale(LC_ALL, \"\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n\n  int number_failed = 0;\n  Suite *s;\n  SRunner *sr;\n\n  s = helper_tokenizer_suite();\n  sr = srunner_create(s);\n\n  srunner_run_all(sr, CK_NORMAL);\n  number_failed = srunner_ntests_failed(sr);\n  srunner_free(sr);\n  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/history-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include <unistd.h>\n\n#include <stdio.h>\n#include <assert.h>\n#include <glib.h>\n#include <history.h>\n#include <string.h>\n\nstatic unsigned int test = 0;\n\n#define TASSERT( a )    {                                \\\n        assert ( a );                                    \\\n        printf ( \"Test %u passed (%s)\\n\", ++test, # a ); \\\n}\n\nconst char *file = \"text\";\n\nstatic void history_test ( void )\n{\n    unlink ( file );\n\n    // Empty list.\n    unsigned int length = 0;\n    char         **retv = history_get_list ( file, &length );\n\n    TASSERT ( retv == NULL );\n    TASSERT ( length == 0 );\n\n    // 1 item\n    history_set ( file, \"aap\" );\n\n    retv = history_get_list ( file, &length );\n\n    TASSERT ( retv != NULL );\n    TASSERT ( length == 1 );\n    TASSERT ( strcmp ( retv[0], \"aap\" ) == 0 );\n\n    g_strfreev ( retv );\n\n    // Remove entry\n    history_remove ( file, \"aap\" );\n\n    length = 0;\n    retv   = history_get_list ( file, &length );\n\n    TASSERT ( retv == NULL );\n    TASSERT ( length == 0 );\n\n    // 2 items\n    history_set ( file, \"aap\" );\n    history_set ( file, \"aap\" );\n\n    retv = history_get_list ( file, &length );\n\n    TASSERT ( retv != NULL );\n    TASSERT ( length == 1 );\n\n    TASSERT ( strcmp ( retv[0], \"aap\" ) == 0 );\n\n    g_strfreev ( retv );\n\n    for ( unsigned int in = length + 1; in < 26; in++ ) {\n        char *p = g_strdup_printf ( \"aap%u\", in );\n        printf ( \"%s- %u\\n\", p, in );\n        history_set ( file, p );\n        retv = history_get_list ( file, &length );\n\n        TASSERT ( retv != NULL );\n        TASSERT ( length == ( in ) );\n\n        g_strfreev ( retv );\n\n        g_free ( p );\n    }\n    // Max 25 entries.\n    history_set ( file, \"blaat\" );\n    retv = history_get_list ( file, &length );\n\n    TASSERT ( retv != NULL );\n    TASSERT ( length == 25 );\n    for ( unsigned int in = 0; in < 24; in++ ) {\n        char *p = g_strdup_printf ( \"aap%i\", in + 2 );\n        TASSERT ( g_strcmp0 ( retv[in], p ) == 0 );\n\n        g_free ( p );\n    }\n\n    g_strfreev ( retv );\n\n    unlink ( file );\n}\n\nint main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )\n{\n    history_test ();\n\n    return 0;\n}\n"
  },
  {
    "path": "test/mode-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include <assert.h>\n#include <glib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"display.h\"\n#include \"rofi.h\"\n#include \"theme.h\"\n#include \"widgets/textbox.h\"\n#include <helper.h>\n#include <keyb.h>\n#include <mode-private.h>\n#include <mode.h>\n#include <modes/help-keys.h>\n\n#include \"rofi-icon-fetcher.h\"\n#include <check.h>\n\nThemeWidget *rofi_theme = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ngboolean rofi_theme_parse_string(G_GNUC_UNUSED const char *string) {\n  return FALSE;\n}\n\ndouble textbox_get_estimated_char_height(void) { return 16.0; }\ndouble textbox_get_estimated_ch(void) { return 9.0; }\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nint monitor_active(G_GNUC_UNUSED workarea *d) { return 0; }\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\nvoid rofi_view_get_current_monitor(G_GNUC_UNUSED int *width,\n                                   G_GNUC_UNUSED int *height) {}\nRofiViewState *rofi_view_get_active(void) { return NULL; }\ngboolean rofi_view_check_action(G_GNUC_UNUSED RofiViewState *state,\n                                G_GNUC_UNUSED BindingsScope scope,\n                                G_GNUC_UNUSED guint action) {\n  return FALSE;\n}\nvoid rofi_view_trigger_action(G_GNUC_UNUSED RofiViewState *state,\n                              G_GNUC_UNUSED BindingsScope scope,\n                              G_GNUC_UNUSED guint action) {}\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\n#ifndef _ck_assert_ptr_null\n/* Pointer against NULL comparison macros with improved output\n * compared to ck_assert(). */\n/* OP may only be == or !=  */\n#define _ck_assert_ptr_null(X, OP)                                             \\\n  do {                                                                         \\\n    const void *_ck_x = (X);                                                   \\\n    ck_assert_msg(_ck_x OP NULL, \"Assertion '%s' failed: %s == %#x\",           \\\n                  #X \" \" #OP \" NULL\", #X, _ck_x);                              \\\n  } while (0)\n\n#define ck_assert_ptr_null(X) _ck_assert_ptr_null(X, ==)\n#define ck_assert_ptr_nonnull(X) _ck_assert_ptr_null(X, !=)\n#endif\nstatic void test_mode_setup(void) {\n  ck_assert_int_eq(mode_init(&help_keys_mode), TRUE);\n}\nstatic void test_mode_teardown(void) { mode_destroy(&help_keys_mode); }\n\nSTART_TEST(test_mode_create) {\n  ck_assert_ptr_nonnull(help_keys_mode.private_data);\n}\nEND_TEST\n\nSTART_TEST(test_mode_destroy) {\n  mode_destroy(&help_keys_mode);\n  ck_assert_ptr_null(help_keys_mode.private_data);\n}\nEND_TEST\n\nSTART_TEST(test_mode_num_items) {\n  unsigned int rows = mode_get_num_entries(&help_keys_mode);\n  ck_assert_int_eq(rows, 82);\n  for (unsigned int i = 0; i < rows; i++) {\n    int state = 0;\n    GList *list = NULL;\n    char *v = mode_get_display_value(&help_keys_mode, i, &state, &list, TRUE);\n    ck_assert_ptr_nonnull(v);\n    g_free(v);\n    v = mode_get_display_value(&help_keys_mode, i, &state, &list, FALSE);\n    ck_assert_ptr_null(v);\n  }\n  mode_destroy(&help_keys_mode);\n}\nEND_TEST\n\nSTART_TEST(test_mode_result) {\n  char *res;\n\n  res = NULL;\n  ck_assert_int_eq(mode_result(&help_keys_mode, MENU_NEXT, &res, 0),\n                   NEXT_DIALOG);\n  g_free(res);\n\n  res = NULL;\n  ck_assert_int_eq(mode_result(&help_keys_mode, MENU_PREVIOUS, &res, 0),\n                   PREVIOUS_DIALOG);\n  g_free(res);\n\n  res = NULL;\n  ck_assert_int_eq(mode_result(&help_keys_mode, MENU_QUICK_SWITCH | 1, &res, 0),\n                   1);\n  g_free(res);\n\n  res = NULL;\n  ck_assert_int_eq(mode_result(&help_keys_mode, MENU_QUICK_SWITCH | 2, &res, 0),\n                   2);\n  g_free(res);\n}\nEND_TEST\n\nSTART_TEST(test_mode_match_entry) {\n  rofi_int_matcher **t = helper_tokenize(\"primary-paste\", FALSE);\n  ck_assert_ptr_nonnull(t);\n\n  ck_assert_int_eq(mode_token_match(&help_keys_mode, t, 0), TRUE);\n  ck_assert_int_eq(mode_token_match(&help_keys_mode, t, 1), FALSE);\n  helper_tokenize_free(t);\n  t = helper_tokenize(\"y-paste\", FALSE);\n  ck_assert_ptr_nonnull(t);\n\n  ck_assert_int_eq(mode_token_match(&help_keys_mode, t, 0), TRUE);\n  ck_assert_int_eq(mode_token_match(&help_keys_mode, t, 1), TRUE);\n  ck_assert_int_eq(mode_token_match(&help_keys_mode, t, 2), FALSE);\n  helper_tokenize_free(t);\n}\nEND_TEST\n\nstatic Suite *mode_suite(void) {\n  Suite *s;\n  TCase *tc_core;\n\n  s = suite_create(\"Mode\");\n\n  /* Core test case */\n  tc_core = tcase_create(\"HelpKeys\");\n  tcase_add_checked_fixture(tc_core, test_mode_setup, test_mode_teardown);\n  tcase_add_test(tc_core, test_mode_create);\n  tcase_add_test(tc_core, test_mode_num_items);\n  tcase_add_test(tc_core, test_mode_result);\n  tcase_add_test(tc_core, test_mode_destroy);\n  tcase_add_test(tc_core, test_mode_match_entry);\n  suite_add_tcase(s, tc_core);\n\n  return s;\n}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  setup_abe();\n  int number_failed = 0;\n  Suite *s;\n  SRunner *sr;\n\n  s = mode_suite();\n  sr = srunner_create(s);\n\n  srunner_run_all(sr, CK_NORMAL);\n  number_failed = srunner_ntests_failed(sr);\n  srunner_free(sr);\n  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/scrollbar-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"display.h\"\n#include \"helper.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"xrmoptions.h\"\n#include <assert.h>\n#include <glib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <widgets/icon.h>\n#include <widgets/listview.h>\n#include <widgets/scrollbar.h>\n#include <widgets/textbox.h>\n#include <widgets/widget-internal.h>\n#include <widgets/widget.h>\nunsigned int test = 0;\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %3u passed (%s)\\n\", ++test, #a);                              \\\n  }\n\n#define TASSERTE(a, b)                                                         \\\n  {                                                                            \\\n    if ((a) == (b)) {                                                          \\\n      printf(\"Test %u passed (%s == %s) (%u == %u)\\n\", ++test, #a, #b, a, b);  \\\n    } else {                                                                   \\\n      printf(\"Test %u failed (%s == %s) (%u != %u)\\n\", ++test, #a, #b, a, b);  \\\n      abort();                                                                 \\\n    }                                                                          \\\n  }\n\nint rofi_is_in_dmenu_mode = 0;\nThemeWidget *rofi_configuration = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nchar *helper_get_theme_path(const char *file, G_GNUC_UNUSED const char **ext,\n                            G_GNUC_UNUSED const char *parent_file) {\n  return g_strdup(file);\n}\ngboolean config_parse_set_property(G_GNUC_UNUSED const Property *p,\n                                   G_GNUC_UNUSED char **error) {\n  return FALSE;\n}\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\n\nchar *rofi_expand_path(G_GNUC_UNUSED const char *path) { return NULL; }\ndouble textbox_get_estimated_char_height(void) { return 16; }\ndouble textbox_get_estimated_ch(void) { return 8.0; }\n\nvoid listview_set_selected(G_GNUC_UNUSED listview *lv,\n                           G_GNUC_UNUSED unsigned int selected) {}\nvoid rofi_view_get_current_monitor(G_GNUC_UNUSED int *width,\n                                   G_GNUC_UNUSED int *height) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  scrollbar *sb = scrollbar_create(NULL, \"scrollbar\");\n  widget_resize(WIDGET(sb), 10, 100);\n\n  scrollbar_set_handle(NULL, 10213);\n  scrollbar_set_max_value(NULL, 10);\n  scrollbar_set_handle_length(NULL, 1000);\n\n  scrollbar_set_max_value(sb, 10000);\n  TASSERTE(sb->length, 10000u);\n  scrollbar_set_handle_length(sb, 10);\n  TASSERTE(sb->pos_length, 10u);\n  scrollbar_set_handle(sb, 5000);\n  TASSERTE(sb->pos, 5000u);\n  scrollbar_set_handle(sb, 15000);\n  TASSERTE(sb->pos, 10000u);\n  scrollbar_set_handle(sb, UINT32_MAX);\n  TASSERTE(sb->pos, 10000u);\n  scrollbar_set_handle_length(sb, 15000);\n  TASSERTE(sb->pos_length, 10000u);\n  scrollbar_set_handle_length(sb, 0);\n  TASSERTE(sb->pos_length, 1u);\n\n  guint cl = scrollbar_scroll_get_line(sb, 10);\n  TASSERTE(cl, 1010u);\n  cl = scrollbar_scroll_get_line(sb, 20);\n  TASSERTE(cl, 2020u);\n  cl = scrollbar_scroll_get_line(sb, 0);\n  TASSERTE(cl, 0u);\n  cl = scrollbar_scroll_get_line(sb, 99);\n  TASSERTE(cl, 9999u);\n  scrollbar_set_handle_length(sb, 1000);\n  cl = scrollbar_scroll_get_line(sb, 10);\n  TASSERTE(cl, 556u);\n  cl = scrollbar_scroll_get_line(sb, 20);\n  TASSERTE(cl, 1667u);\n  cl = scrollbar_scroll_get_line(sb, 0);\n  TASSERTE(cl, 0u);\n  cl = scrollbar_scroll_get_line(sb, 99);\n  TASSERTE(cl, 9999u);\n\n  widget_free(WIDGET(sb));\n}\n"
  },
  {
    "path": "test/textbox-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include <unistd.h>\n\n#include \"display.h\"\n#include \"settings.h\"\n#include \"xrmoptions.h\"\n#include <assert.h>\n#include <glib.h>\n#include <history.h>\n#include <rofi.h>\n#include <cairo.h>\n#include \"display.h\"\n#include \"settings.h\"\n#include \"xrmoptions.h\"\n#include <stdio.h>\n#include <string.h>\n#include <widgets/textbox.h>\n\n#include \"rofi-icon-fetcher.h\"\nstatic int test = 0;\nunsigned int normal_window_mode = 0;\nint rofi_is_in_dmenu_mode = 0;\n\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %3i passed (%s)\\n\", ++test, #a);                              \\\n  }\n\n#include \"view.h\"\n\nThemeWidget *rofi_configuration = NULL;\n\nvoid rofi_timings_tick(G_GNUC_UNUSED const char *file,\n                       G_GNUC_UNUSED char const *str, G_GNUC_UNUSED int line,\n                       G_GNUC_UNUSED char const *msg);\nvoid rofi_timings_tick(G_GNUC_UNUSED const char *file,\n                       G_GNUC_UNUSED char const *str, G_GNUC_UNUSED int line,\n                       G_GNUC_UNUSED char const *msg) {}\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ngboolean config_parse_set_property(G_GNUC_UNUSED const Property *p,\n                                   G_GNUC_UNUSED char **error) {\n  return FALSE;\n}\n\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_view_queue_redraw(void) {}\nvoid rofi_view_get_current_monitor(G_GNUC_UNUSED int *width,\n                                   G_GNUC_UNUSED int *height) {}\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return FALSE;\n}\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  cairo_surface_t *surf =\n      cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100);\n  cairo_t *draw = cairo_create(surf);\n  PangoContext *p = pango_cairo_create_context(draw);\n\n  textbox_setup();\n  textbox_set_pango_context(\"default\", p);\n\n  textbox *box = textbox_create(NULL, WIDGET_TYPE_TEXTBOX_TEXT, \"textbox\",\n                                TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT,\n                                NORMAL, \"test\", 0, 0);\n  TASSERT(box != NULL);\n\n  textbox_keybinding(box, MOVE_END);\n  TASSERT(box->cursor == 4);\n  textbox_cursor(box, -1);\n  TASSERT(box->cursor == 0);\n  textbox_cursor(box, 8);\n  TASSERT(box->cursor == 4);\n  textbox_cursor(box, 2);\n  TASSERT(box->cursor == 2);\n  textbox_insert(box, 3, \"bo\", 2);\n  TASSERT(strcmp(box->text, \"tesbot\") == 0);\n  textbox_keybinding(box, MOVE_END);\n  TASSERT(box->cursor == 6);\n\n  TASSERT(widget_get_width(WIDGET(box)) > 0);\n  TASSERT(textbox_get_height(box) > 0);\n\n  TASSERT(widget_get_width(WIDGET(box)) >= textbox_get_font_width(box));\n  TASSERT(textbox_get_height(box) >= textbox_get_font_height(box));\n\n  TASSERT(textbox_get_estimated_char_width() > 0);\n\n  textbox_keybinding(box, REMOVE_CHAR_BACK);\n  TASSERT(strcmp(box->text, \"tesbo\") == 0);\n  TASSERT(box->cursor == 5);\n\n  textbox_keybinding(box, MOVE_CHAR_BACK);\n  TASSERT(box->cursor == 4);\n  textbox_keybinding(box, REMOVE_CHAR_FORWARD);\n  TASSERT(strcmp(box->text, \"tesb\") == 0);\n  textbox_keybinding(box, MOVE_CHAR_BACK);\n  TASSERT(box->cursor == 3);\n  textbox_keybinding(box, MOVE_CHAR_FORWARD);\n  TASSERT(box->cursor == 4);\n  textbox_keybinding(box, MOVE_CHAR_FORWARD);\n  TASSERT(box->cursor == 4);\n  // Cursor after delete section.\n  textbox_delete(box, 0, 1);\n  TASSERT(strcmp(box->text, \"esb\") == 0);\n  TASSERT(box->cursor == 3);\n  // Cursor before delete.\n  textbox_text(box, \"aap noot mies\");\n  TASSERT(strcmp(box->text, \"aap noot mies\") == 0);\n  textbox_cursor(box, 3);\n  TASSERT(box->cursor == 3);\n  textbox_delete(box, 3, 6);\n  TASSERT(strcmp(box->text, \"aapmies\") == 0);\n  TASSERT(box->cursor == 3);\n\n  // Cursor within delete\n  textbox_text(box, \"aap noot mies\");\n  TASSERT(strcmp(box->text, \"aap noot mies\") == 0);\n  textbox_cursor(box, 5);\n  TASSERT(box->cursor == 5);\n  textbox_delete(box, 3, 6);\n  TASSERT(strcmp(box->text, \"aapmies\") == 0);\n  TASSERT(box->cursor == 3);\n  // Cursor after delete.\n  textbox_text(box, \"aap noot mies\");\n  TASSERT(strcmp(box->text, \"aap noot mies\") == 0);\n  textbox_cursor(box, 11);\n  TASSERT(box->cursor == 11);\n  textbox_delete(box, 3, 6);\n  TASSERT(strcmp(box->text, \"aapmies\") == 0);\n  TASSERT(box->cursor == 5);\n\n  textbox_text(box, \"aap noot mies\");\n  textbox_cursor(box, 8);\n  textbox_keybinding(box, REMOVE_WORD_BACK);\n  TASSERT(box->cursor == 4);\n  TASSERT(strcmp(box->text, \"aap  mies\") == 0);\n  textbox_keybinding(box, REMOVE_TO_EOL);\n  TASSERT(box->cursor == 4);\n  TASSERT(strcmp(box->text, \"aap \") == 0);\n  textbox_text(box, \"aap noot mies\");\n  textbox_cursor(box, 8);\n  textbox_keybinding(box, REMOVE_WORD_FORWARD);\n  TASSERT(strcmp(box->text, \"aap noot\") == 0);\n  textbox_keybinding(box, MOVE_FRONT);\n  TASSERT(box->cursor == 0);\n  textbox_keybinding(box, CLEAR_LINE);\n  TASSERT(strcmp(box->text, \"\") == 0);\n  textbox_text(box, \"aap noot mies\");\n  textbox_keybinding(box, MOVE_END);\n  textbox_keybinding(box, MOVE_WORD_BACK);\n  TASSERT(box->cursor == 9);\n  textbox_keybinding(box, MOVE_WORD_BACK);\n  TASSERT(box->cursor == 4);\n  textbox_keybinding(box, REMOVE_TO_SOL);\n  TASSERT(strcmp(box->text, \"noot mies\") == 0);\n  TASSERT(box->cursor == 0);\n\n  textbox_font(box, HIGHLIGHT);\n  // textbox_draw ( box, draw );\n\n  widget_move(WIDGET(box), 12, 13);\n  TASSERT(box->widget.x == 12);\n  TASSERT(box->widget.y == 13);\n\n  widget_free(WIDGET(box));\n  textbox_cleanup();\n}\n"
  },
  {
    "path": "test/theme-parser-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"css-colors.h\"\n#include \"display.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"settings.h\"\n#include \"theme.h\"\n#include \"widgets/textbox.h\"\n#include \"widgets/widget-internal.h\"\n#include <assert.h>\n#include <glib.h>\n#include <helper.h>\n#include <locale.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#define REAL_COMPARE_DELTA 0.001\n\nint rofi_is_in_dmenu_mode = 0;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nvoid rofi_clear_error_messages(void) {}\nvoid rofi_clear_warning_messages(void) {}\nuint32_t\nrofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED G_GNUC_UNUSED const int wsize,\n                                 G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return TRUE;\n}\n\nvoid rofi_view_get_current_monitor(int *width, int *height) {\n  if (width) {\n    *width = 1920;\n  }\n  if (height) {\n    *height = 1080;\n  }\n}\ndouble textbox_get_estimated_char_height(void) { return 16.0; }\n\ndouble textbox_get_estimated_ch(void) { return 8.0; }\n\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\n#ifndef _ck_assert_ptr_null\n/* Pointer against NULL comparison macros with improved output\n * compared to ck_assert(). */\n/* OP may only be == or !=  */\n#define _ck_assert_ptr_null(X, OP)                                             \\\n  do {                                                                         \\\n    const void *_ck_x = (X);                                                   \\\n    ck_assert_msg(_ck_x OP NULL, \"Assertion '%s' failed: %s == %#x\",           \\\n                  #X \" \" #OP \" NULL\", #X, _ck_x);                              \\\n  } while (0)\n\n#define ck_assert_ptr_null(X) _ck_assert_ptr_null(X, ==)\n#define ck_assert_ptr_nonnull(X) _ck_assert_ptr_null(X, !=)\n#endif\n\ngboolean error = FALSE;\nGString *error_msg = NULL;\ngboolean warning = FALSE;\nGString *warning_msg = NULL;\nvoid rofi_add_error_message(GString *msg) {\n  ck_assert_ptr_null(error_msg);\n  error_msg = msg;\n  error = TRUE;\n}\nvoid rofi_add_warning_message(GString *msg) {\n  ck_assert_ptr_null(warning_msg);\n  warning_msg = msg;\n  warning = TRUE;\n}\n\nstatic void theme_parser_setup(void) { error = 0; }\nstatic void theme_parser_teardown(void) {\n  ck_assert_ptr_null(error_msg);\n  ck_assert_int_eq(error, 0);\n  rofi_theme_free(rofi_theme);\n  rofi_theme = NULL;\n}\n\nSTART_TEST(test_core_empty_string) {\n  rofi_theme_parse_string(\"\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n}\nEND_TEST\nSTART_TEST(test_core_empty_global_section) {\n  rofi_theme_parse_string(\" * {}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n}\nEND_TEST\nSTART_TEST(test_core_empty_section) {\n  rofi_theme_parse_string(\" #test {}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  ck_assert_ptr_nonnull(rofi_theme->widgets);\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  // ck_assert_str_eq ( rofi_theme->widgets[3]->name, \"test\" );\n  // ck_assert_ptr_null ( rofi_theme->widgets[3]->properties );\n  // ck_assert_ptr_eq ( rofi_theme->widgets[3]->parent, rofi_theme );\n}\nEND_TEST\nSTART_TEST(test_core_error_root) {\n  rofi_theme_parse_string(\"Blaat\");\n  ck_assert_int_eq(error, 1);\n  ck_assert_ptr_null(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  // ck_assert_ptr_null ( rofi_theme->properties );\n  // ck_assert_ptr_null ( rofi_theme->parent );\n  const char *error_str =\n      \"<big><b>Error while parsing theme:</b></big> <i>Blaat</i>\\n\"\n      \"\tParser error: <span size=\\\"smaller\\\" style=\\\"italic\\\">syntax error, \"\n      \"unexpected end of file, expecting &quot;bracket open \"\n      \"(&apos;{&apos;)&quot; or &quot;Selector separator \"\n      \"(&apos;,&apos;)&quot;</span>\\n\"\n      \"\tLocation:     line 1 column 6 to line 1 column 6\\n\";\n  ck_assert_str_eq(error_msg->str, error_str);\n\n  g_string_free(error_msg, TRUE);\n  error_msg = NULL;\n  error = 0;\n}\nEND_TEST\n\nSTART_TEST(test_core_comments) {\n  rofi_theme_parse_string(\"// Random comments // /*test */\");\n  rofi_theme_parse_string(\"/* test /* aap */ */\");\n  rofi_theme_parse_string(\"// Random comments\\n// /*test */\");\n  rofi_theme_parse_string(\"/* test \\n*\\n* /* aap */ */\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n\n  // Test comment on last lines\n  rofi_theme_parse_string(\"// c++ style\");\n  rofi_theme_parse_string(\"/* c style\");\n}\nEND_TEST\nSTART_TEST(test_core_newline) {\n  rofi_theme_parse_string(\"\\r\\n\\n\\r\\n\\n/*\\r\\n*/\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n}\nEND_TEST\n\nSTART_TEST(test_properties_boolean) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  /** Boolean property */\n  rofi_theme_parse_string(\"*{ test: true; test2:/* inline */false; }\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_nonnull(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"test\", FALSE), TRUE);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"test2\", TRUE), FALSE);\n}\nEND_TEST\n\nSTART_TEST(test_properties_boolean_reference) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { test: true; test2:/* inline */false;} *{ a:@test; b:@test2;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"test\", FALSE), TRUE);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"b\", TRUE), FALSE);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"a\", FALSE), TRUE);\n  ck_assert_int_eq(rofi_theme_get_boolean(&wid, \"test2\", TRUE), FALSE);\n}\nEND_TEST\n\nSTART_TEST(test_properties_distance_em) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10em;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_int_eq(p.left.base.distance, 10);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_EM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_em_linestyle) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { sol: 1.3em solid; dash: 1.5em dash;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"sol\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 1.3, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_EM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n\n  p = rofi_theme_get_padding(&wid, \"dash\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 1.5, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_EM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_DASH);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_ch) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10ch;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_int_eq(p.left.base.distance, 10);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_CH);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_ch_linestyle) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { sol: 1.3ch solid; dash: 1.5ch dash;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"sol\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 1.3, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_CH);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n\n  p = rofi_theme_get_padding(&wid, \"dash\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 1.5, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_CH);\n  ck_assert_int_eq(p.left.style, ROFI_HL_DASH);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_px) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10px;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_px_linestyle) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { sol: 10px solid; dash: 14px dash;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"sol\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n  p = rofi_theme_get_padding(&wid, \"dash\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 14.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_int_eq(p.left.style, ROFI_HL_DASH);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_percent) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10%;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PERCENT);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n}\nEND_TEST\nSTART_TEST(test_properties_distance_percent_linestyle) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { sol: 10% solid; dash: 10% dash;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"sol\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PERCENT);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n  p = rofi_theme_get_padding(&wid, \"dash\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PERCENT);\n  ck_assert_int_eq(p.left.style, ROFI_HL_DASH);\n}\nEND_TEST\n\nSTART_TEST(test_properties_distance_mm) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10mm;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_MM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n}\nEND_TEST\n\nSTART_TEST(test_properties_distance_mm_linestyle) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { sol: 10mm solid; dash: 10mm dash;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_EM, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_DASH};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"sol\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10.0, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_MM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_SOLID);\n  p = rofi_theme_get_padding(&wid, \"dash\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_MM);\n  ck_assert_int_eq(p.left.style, ROFI_HL_DASH);\n}\nEND_TEST\nSTART_TEST(test_properties_position) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { center: center; east: east; west: west; south: \"\n                          \"south; north:north;}\");\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"center\", WL_SOUTH),\n                   WL_CENTER);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"south\", WL_EAST), WL_SOUTH);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"east\", WL_WEST), WL_EAST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"west\", WL_NORTH), WL_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"north\", WL_CENTER), WL_NORTH);\n\n  rofi_theme_parse_string(\"* { southwest: southwest; southeast: southeast; \"\n                          \"northwest: northwest; northeast:northeast;}\");\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"southwest\", WL_EAST),\n                   WL_SOUTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"southeast\", WL_WEST),\n                   WL_SOUTH_EAST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"northwest\", WL_NORTH),\n                   WL_NORTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"northeast\", WL_CENTER),\n                   WL_NORTH_EAST);\n  rofi_theme_parse_string(\"* { southwest: south west; southeast: south east; \"\n                          \"northwest: north west; northeast:north east;}\");\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"southwest\", WL_EAST),\n                   WL_SOUTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"southeast\", WL_WEST),\n                   WL_SOUTH_EAST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"northwest\", WL_NORTH),\n                   WL_NORTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"northeast\", WL_CENTER),\n                   WL_NORTH_EAST);\n  rofi_theme_parse_string(\"* { westsouth: westsouth; eastsouth: eastsouth; \"\n                          \"westnorth: westnorth; eastnorth:eastnorth;}\");\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"westsouth\", WL_EAST),\n                   WL_SOUTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"eastsouth\", WL_WEST),\n                   WL_SOUTH_EAST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"westnorth\", WL_NORTH),\n                   WL_NORTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"eastnorth\", WL_CENTER),\n                   WL_NORTH_EAST);\n  rofi_theme_parse_string(\"* { westsouth: west south; eastsouth: east south; \"\n                          \"westnorth: west north; eastnorth:east north;}\");\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"westsouth\", WL_EAST),\n                   WL_SOUTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"eastsouth\", WL_WEST),\n                   WL_SOUTH_EAST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"westnorth\", WL_NORTH),\n                   WL_NORTH_WEST);\n  ck_assert_int_eq(rofi_theme_get_position(&wid, \"eastnorth\", WL_CENTER),\n                   WL_NORTH_EAST);\n  rofi_theme_parse_string(\"* { westeast: west east;}\");\n  // Should return error.\n  // TODO: check error message.\n  g_string_free(error_msg, TRUE);\n  error_msg = NULL;\n  error = 0;\n}\nEND_TEST\n\nSTART_TEST(test_properties_style) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { none: none; bold: bold; underline: underline; \"\n                          \"italic: italic; st: italic strikethrough;}\");\n  RofiHighlightColorStyle th = {ROFI_HL_BOLD, {0.0, 0.0, 0.0, 0.0}};\n  th = rofi_theme_get_highlight(&wid, \"none\", th);\n  ck_assert_int_eq(th.style, ROFI_HL_NONE);\n  th = rofi_theme_get_highlight(&wid, \"underline\", th);\n  ck_assert_int_eq(th.style, ROFI_HL_UNDERLINE);\n  th = rofi_theme_get_highlight(&wid, \"italic\", th);\n  ck_assert_int_eq(th.style, ROFI_HL_ITALIC);\n  th = rofi_theme_get_highlight(&wid, \"bold\", th);\n  ck_assert_int_eq(th.style, ROFI_HL_BOLD);\n  th = rofi_theme_get_highlight(&wid, \"st\", th);\n  ck_assert_int_eq(th.style, ROFI_HL_ITALIC | ROFI_HL_STRIKETHROUGH);\n}\nEND_TEST\nSTART_TEST(test_properties_style2) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n\n  rofi_theme_parse_string(\n      \"* { boldu: bold underline ; boldi: bold italic; underlinei: underline \"\n      \"italic; italicu: italic underline;}\");\n  RofiHighlightColorStyle th = {ROFI_HL_BOLD, {0.0, 0.0, 0.0, 0.0}};\n  th = rofi_theme_get_highlight(&wid, \"boldu\", th);\n  ck_assert_int_eq(th.style, (ROFI_HL_UNDERLINE | ROFI_HL_BOLD));\n  th = rofi_theme_get_highlight(&wid, \"boldi\", th);\n  ck_assert_int_eq(th.style, (ROFI_HL_ITALIC | ROFI_HL_BOLD));\n  th = rofi_theme_get_highlight(&wid, \"underlinei\", th);\n  ck_assert_int_eq(th.style, (ROFI_HL_ITALIC | ROFI_HL_UNDERLINE));\n  th = rofi_theme_get_highlight(&wid, \"italicu\", th);\n  ck_assert_int_eq(th.style, (ROFI_HL_ITALIC | ROFI_HL_UNDERLINE));\n}\nEND_TEST\nSTART_TEST(test_properties_style_color) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { comb: bold #123; }\");\n  RofiHighlightColorStyle th = {ROFI_HL_BOLD, {0.0, 0.0, 0.0, 0.0}};\n  th = rofi_theme_get_highlight(&wid, \"comb\", th);\n  ck_assert_int_eq(th.style, (ROFI_HL_BOLD | ROFI_HL_COLOR));\n  ck_assert_double_eq_tol(th.color.red, (1 / 15.0), REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(th.color.green, (2 / 15.0), REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(th.color.blue, (3 / 15.0), REAL_COMPARE_DELTA);\n}\nEND_TEST\n\nSTART_TEST(test_properties_color_h3) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: #F00; green: #0F0; blue: #00F; }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\n\nSTART_TEST(test_properties_color_h6) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: #FF0000; green: #00FF00; blue: #0000FF; }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\n\nSTART_TEST(test_properties_color_h4) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: #F003; green: #0F02; blue: #00F1; }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 7.5, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 15.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_h8) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { red: #FF000033; green: #00FF0022; blue: #0000FF11; }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 7.5, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 15.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgb) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: rgb(100%,0%,0%); green: rgb(0%,100%,0%); \"\n                          \"blue: rgb(0%,0%,100%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgba_p) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { red: rgba(100%,0%,0%,0.3); green: rgba(0%,100%,0%,0.2); blue: \"\n      \"rgba(0%,0%,100%,0.7); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.7, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgba_percent_p) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { red: rgba(100%,0%,0%,30%); green: rgba(0%,100%,0%,20%); blue: \"\n      \"rgba(0% 0% 100%/70.0%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.7, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgb_p) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { red: rgb(255,0,0); green: rgb(0,255,0); blue: rgb(0,0,255); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgba) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: rgba(255,0,0,0.3); green: \"\n                          \"rgba(0,255,0,0.2); blue: rgba(0 0 255 /0.7); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  ck_assert_ptr_nonnull(twid);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.7, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_rgba_percent) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { red: rgba(255,0,0,30%); green: \"\n                          \"rgba(0,255,0,20%); blue: rgba(0,0,255,70.0%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.7, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_argb) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { red: argb:33FF0000; green: argb:2200FF00; blue: argb:110000FF; }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"red\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.2, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"green\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 7.5, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 1, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, REAL_COMPARE_DELTA);\n  p = rofi_theme_find_property(twid, P_COLOR, \"blue\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1 / 15.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.green, 0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.blue, 1, REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hsl) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test1: hsl(127,40%,66.66666%); test2: hsl(0, \"\n                          \"100%, 50%); testa: hsl(127,40%, 66.66666%, 30%);}\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"testa\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hsla) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test1: hsla(127,40%,66.66666%, 40%); test2: \"\n                          \"hsla(0, 100%, 50%,55%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.4, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.55, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hsl_ws) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { test1: hsl(127 40% 66.66666%); test2: hsl(0  100%  50%); testa: \"\n      \"hsl(127 40%  66.66666%  / 30%);}\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"testa\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hsla_ws) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test1: hsla(127 40% 66.66666% / 0.3); test2: \"\n                          \"hsla(0  100%  50%/ 55%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.3, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x88 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0xcd / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0x90 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.55, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hwb) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test1: hwb(190,65%,0%); test2: hwb(265, 31%, \"\n                          \"29%); testa: hwb(265, 31%, 29%, 40%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x7a / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0x4f / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0xb5 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 166 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 240 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 255 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"testa\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.4, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x7a / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0x4f / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0xb5 / 255.0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_hwb_ws) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { test1: hwb(190 deg 65 %0%); test2: hwb(295 grad 31% 29%);testa: \"\n      \"hwb(0.736 turn 31% 29% / 40%); rada: hwb(0.2 rad 30% 30%/40%); }\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x7a / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0x4f / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0xb5 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 166 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 240 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 255 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"testa\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.4, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x7a / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0x4f / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0xb5 / 255.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"rada\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 0.4, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0.7, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0.376, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0.3, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_cmyk) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { test1: cmyk ( 41%, 0%, 100%, 0%); test2: cmyk ( 0, 1.0, 1.0, 0);}\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x96 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 1.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_cmyk_ws) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { test1: cmyk ( 41% 0% 100% 0%); test2: cmyk ( 0 1.0 1.0 0);}\");\n  ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n\n  Property *p = rofi_theme_find_property(twid, P_COLOR, \"test1\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 0x96 / 255.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 1.0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0.0, 0.004);\n  p = rofi_theme_find_property(twid, P_COLOR, \"test2\", FALSE);\n  ck_assert_ptr_nonnull(p);\n  ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n  ck_assert_double_eq_tol(p->value.color.red, 1, 0.004);\n  ck_assert_double_eq_tol(p->value.color.green, 0, 0.004);\n  ck_assert_double_eq_tol(p->value.color.blue, 0, 0.004);\n}\nEND_TEST\nSTART_TEST(test_properties_color_names) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  for (unsigned int iter = 0; iter < num_CSSColors; iter++) {\n    char *str = g_strdup_printf(\"* { color: %s;}\", CSSColors[iter].name);\n    rofi_theme_parse_string(str);\n    ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n    Property *p = rofi_theme_find_property(twid, P_COLOR, \"text-color\", FALSE);\n    ck_assert_ptr_nonnull(p);\n    ck_assert_double_eq_tol(p->value.color.alpha, 1.0, REAL_COMPARE_DELTA);\n    ck_assert_double_eq_tol(p->value.color.red, CSSColors[iter].r / 255.0,\n                            0.004);\n    ck_assert_double_eq_tol(p->value.color.green, CSSColors[iter].g / 255.0,\n                            0.004);\n    ck_assert_double_eq_tol(p->value.color.blue, CSSColors[iter].b / 255.0,\n                            0.004);\n\n    g_free(str);\n  }\n  {\n    rofi_theme_parse_string(\"* {color: transparent;}\");\n    ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n    Property *p = rofi_theme_find_property(twid, P_COLOR, \"text-color\", FALSE);\n    ck_assert_ptr_nonnull(p);\n    ck_assert_double_eq_tol(p->value.color.alpha, 0.0, REAL_COMPARE_DELTA);\n    ck_assert_double_eq_tol(p->value.color.red, 0.0, 0.004);\n    ck_assert_double_eq_tol(p->value.color.green, 0.0, 0.004);\n    ck_assert_double_eq_tol(p->value.color.blue, 0.0, 0.004);\n  }\n}\nEND_TEST\nSTART_TEST(test_properties_color_names_alpha) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  for (unsigned int iter = 0; iter < num_CSSColors; iter++) {\n    char *str = g_strdup_printf(\"* { color: %s / %d %%;}\", CSSColors[iter].name,\n                                iter % 101);\n    rofi_theme_parse_string(str);\n    ThemeWidget *twid = rofi_theme_find_widget(wid.name, wid.state, FALSE);\n    Property *p = rofi_theme_find_property(twid, P_COLOR, \"text-color\", FALSE);\n    ck_assert_ptr_nonnull(p);\n    ck_assert_double_eq_tol(p->value.color.alpha, (iter % 101) / 100.0,\n                            REAL_COMPARE_DELTA);\n    ck_assert_double_eq_tol(p->value.color.red, CSSColors[iter].r / 255.0,\n                            0.004);\n    ck_assert_double_eq_tol(p->value.color.green, CSSColors[iter].g / 255.0,\n                            0.004);\n    ck_assert_double_eq_tol(p->value.color.blue, CSSColors[iter].b / 255.0,\n                            0.004);\n\n    g_free(str);\n  }\n}\nEND_TEST\nSTART_TEST(test_properties_padding_2) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10px 20px;}\");\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 20, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.right.base.distance, 20, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.right.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.top.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.top.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.bottom.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.bottom.base.type, ROFI_PU_PX);\n}\nEND_TEST\nSTART_TEST(test_properties_padding_3) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10px 30px 20px;}\");\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 30, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.right.base.distance, 30, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.right.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.top.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.top.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.bottom.base.distance, 20, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.bottom.base.type, ROFI_PU_PX);\n}\nEND_TEST\nSTART_TEST(test_properties_padding_4) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 10px 30px 20px 40px;}\");\n  RofiDistance d = (RofiDistance){\n      {1, ROFI_PU_PX, ROFI_DISTANCE_MODIFIER_NONE, NULL, NULL}, ROFI_HL_SOLID};\n  RofiPadding pi = (RofiPadding){d, d, d, d};\n  RofiPadding p = rofi_theme_get_padding(&wid, \"test\", pi);\n  ck_assert_double_eq_tol(p.left.base.distance, 40, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.left.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.right.base.distance, 30, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.right.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.top.base.distance, 10, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.top.base.type, ROFI_PU_PX);\n  ck_assert_double_eq_tol(p.bottom.base.distance, 20, REAL_COMPARE_DELTA);\n  ck_assert_int_eq(p.bottom.base.type, ROFI_PU_PX);\n}\nEND_TEST\n\nSTART_TEST(test_properties_string_escape) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"* { font: \\\"aap\\\" noot\\\" mies \\\";\\ntest: \\\"'123.432'\\\"; }\");\n\n  const char *str = rofi_theme_get_string(&wid, \"font\", NULL);\n  ck_assert_ptr_nonnull(str);\n  ck_assert_int_eq(g_utf8_collate(str, \"aap\\\" noot\\\" mies \"), 0);\n  const char *str2 = rofi_theme_get_string(&wid, \"test\", NULL);\n  ck_assert_ptr_nonnull(str2);\n  ck_assert_int_eq(g_utf8_collate(str2, \"'123.432'\"), 0);\n}\nEND_TEST\nSTART_TEST(test_properties_string) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { font: \\\"blaat€\\\"; test: 123.432; }\");\n\n  const char *str = rofi_theme_get_string(&wid, \"font\", NULL);\n  ck_assert_ptr_nonnull(str);\n  ck_assert_int_eq(g_utf8_collate(str, \"blaat€\"), 0);\n}\nEND_TEST\nSTART_TEST(test_properties_double) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { test: 123.432; }\");\n  ck_assert_double_eq_tol(rofi_theme_get_double(&wid, \"test\", 0.0), 123.432,\n                          REAL_COMPARE_DELTA);\n}\nEND_TEST\nSTART_TEST(test_properties_integer) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { yoffset: 4; }\");\n  ck_assert_int_eq(rofi_theme_get_integer(&wid, \"yoffset\", 0), 4);\n}\nEND_TEST\n\nSTART_TEST(test_properties_orientation) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { vert: vertical; hori: horizontal; }\");\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"vert\", ROFI_ORIENTATION_HORIZONTAL),\n      ROFI_ORIENTATION_VERTICAL);\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"hori\", ROFI_ORIENTATION_VERTICAL),\n      ROFI_ORIENTATION_HORIZONTAL);\n  // default propagation\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"notfo\", ROFI_ORIENTATION_HORIZONTAL),\n      ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"notfo\", ROFI_ORIENTATION_VERTICAL),\n      ROFI_ORIENTATION_VERTICAL);\n}\nEND_TEST\nSTART_TEST(test_properties_orientation_case) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { vert: Vertical; hori: HoriZonTal;}\");\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"vert\", ROFI_ORIENTATION_HORIZONTAL),\n      ROFI_ORIENTATION_VERTICAL);\n  ck_assert_int_eq(\n      rofi_theme_get_orientation(&wid, \"hori\", ROFI_ORIENTATION_VERTICAL),\n      ROFI_ORIENTATION_HORIZONTAL);\n}\nEND_TEST\nSTART_TEST(test_properties_cursor) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { def: default; ptr: pointer; txt: text; }\");\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"def\", ROFI_CURSOR_TEXT),\n                   ROFI_CURSOR_DEFAULT);\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"ptr\", ROFI_CURSOR_DEFAULT),\n                   ROFI_CURSOR_POINTER);\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"txt\", ROFI_CURSOR_DEFAULT),\n                   ROFI_CURSOR_TEXT);\n}\nEND_TEST\nSTART_TEST(test_properties_cursor_case) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\"* { def: dEfault; ptr: POINter; txt: tExt; }\");\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"def\", ROFI_CURSOR_TEXT),\n                   ROFI_CURSOR_DEFAULT);\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"ptr\", ROFI_CURSOR_DEFAULT),\n                   ROFI_CURSOR_POINTER);\n  ck_assert_int_eq(rofi_theme_get_cursor_type(&wid, \"txt\", ROFI_CURSOR_DEFAULT),\n                   ROFI_CURSOR_TEXT);\n}\nEND_TEST\nSTART_TEST(test_properties_list) {\n  widget wid;\n  wid.name = \"blaat\";\n  wid.state = NULL;\n  rofi_theme_parse_string(\n      \"#blaat { liste: [];  list1: [ one ]; list2: [ one, two ];}\");\n  GList *list = rofi_theme_get_list_strings(&wid, \"liste\");\n  ck_assert_ptr_null(list);\n  list = rofi_theme_get_list_strings(&wid, \"list1\");\n  ck_assert_ptr_nonnull(list);\n  ck_assert_str_eq((char *)list->data, \"one\");\n  g_list_free_full(list, (GDestroyNotify)g_free);\n\n  list = rofi_theme_get_list_strings(&wid, \"list2\");\n  ck_assert_ptr_nonnull(list);\n  ck_assert_int_eq(g_list_length(list), 2);\n  list = g_list_first(list);\n  ck_assert_str_eq((char *)list->data, \"one\");\n  ck_assert_str_eq((char *)list->next->data, \"two\");\n  g_list_free_full(list, (GDestroyNotify)g_free);\n}\nEND_TEST\nSTART_TEST(test_configuration) {\n  rofi_theme_parse_string(\"configuration { font: \\\"blaat€\\\"; yoffset: 4; }\");\n  ck_assert_int_eq(g_utf8_collate(config.menu_font, \"blaat€\"), 0);\n  ck_assert_int_eq(config.y_offset, 4);\n}\nEND_TEST\n\nSTART_TEST(test_parse_file_empty) {\n  rofi_theme_parse_file(\"/dev/null\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n}\nEND_TEST\nSTART_TEST(test_parse_file_not_existing) {\n  rofi_theme_parse_file(\"/not-existing-file.rasi\");\n  ck_assert_ptr_null(rofi_theme);\n  ck_assert_int_eq(error, 1);\n  ck_assert_str_eq(\n      error_msg->str,\n      \"Failed to open theme: <i>/not-existing-file.rasi</i>\\nError: <b>No such \"\n      \"file or directory</b>\");\n\n  g_string_free(error_msg, TRUE);\n  error_msg = NULL;\n  error = 0;\n}\nEND_TEST\nSTART_TEST(test_import_empty) {\n  rofi_theme_parse_string(\"@import \\\"/dev/null\\\"\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n}\nEND_TEST\n\nSTART_TEST(test_core_properties_error) {\n  rofi_theme_parse_string(\" * { test: cmky(a,e,3); }\");\n  const char *errstr =\n      \"<big><b>Error while parsing theme:</b></big> <i> * { test: cmky(a,e,3); \"\n      \"}</i>\\n\"\n      \"\tParser error: <span size=\\\"smaller\\\" style=\\\"italic\\\">syntax error, \"\n      \"unexpected invalid property value</span>\\n\"\n      \"\tLocation:     line 1 column 11 to line 1 column 23\\n\";\n  ck_assert_int_eq(error, 1);\n  ck_assert_str_eq(error_msg->str, errstr);\n  g_string_free(error_msg, TRUE);\n  error_msg = NULL;\n  error = 0;\n\n  const char *errstr2 =\n      \"<big><b>Error while parsing theme:</b></big> <i></i>\\n\"\n      \"\tParser error: <span size=\\\"smaller\\\" style=\\\"italic\\\">Value out of \"\n      \"range: \\n\"\n      \"\t\tValue: X = 500.00;\\n\"\n      \"\t\tRange: 0.00 &lt;= X &lt;= 360.00.</span>\\n\"\n      \"\tLocation:     line 0 column 15 to line 0 column 18\\n\";\n  rofi_theme_parse_string(\" * { test: hsl(500, 100% 10% ); }\");\n  ck_assert_int_eq(error, 1);\n  ck_assert_str_eq(error_msg->str, errstr2);\n  g_string_free(error_msg, TRUE);\n  error_msg = NULL;\n  error = 0;\n}\nEND_TEST\n\nSTART_TEST(test_import_error) {\n  rofi_theme_parse_string(\"@import \\\"/non-existing-file.rasi\\\"\");\n\n  const char *errstr = \"Failed to open theme: <i>/non-existing-file.rasi</i>\\n\"\n                       \"Error: <b>No such file or directory</b>\";\n  ck_assert_int_eq(warning, 1);\n  ck_assert_str_eq(warning_msg->str, errstr);\n  g_string_free(warning_msg, TRUE);\n  warning_msg = NULL;\n  warning = 0;\n}\nEND_TEST\nSTART_TEST(test_prepare_array) {\n  widget wid;\n  wid.name = \"element-text\";\n  wid.state = \"normal.normal\";\n  rofi_theme_parse_string(\"element-text  { tabs: [ 10, 20px, 30px, 40px ];}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  GList *l = rofi_theme_get_list_distance(&wid, \"tabs\");\n\n  ck_assert_int_eq(g_list_length(l), 4);\n\n  int i = 10;\n  for (GList *iter = g_list_first(l); iter != NULL; iter = g_list_next(iter)) {\n    RofiDistance *d = (RofiDistance *)iter->data;\n    ck_assert_int_eq(d->base.distance, i);\n    i += 10;\n  }\n\n  g_list_free_full(l, g_free);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_math_floor) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1024 floor 30 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1020);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_ceil) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1024 ceil 30 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1050);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_round) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1036 round 30 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1050);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_add) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1036 + 30 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1066);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_subtract) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1036 - 30 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1006);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_multiply) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 256*4 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 1024);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_modulo) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 255 modulo 4 modulo 5 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 3);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_math_min) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 256 min 4 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 4);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_math_max) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 256 max 4 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 256);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_math_failure) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( 1/2 * 500 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 250);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_math_failure2) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc( -16/2 * 1.5 );}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, -12);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure3) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(10+3);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 13);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure4) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(10.0+3.2);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 13);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure5) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(10-3);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 7);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure6) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(10.0-3.2);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 6);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure7) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(-10--3);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, -7);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure8) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: calc(-10.0--3.2);}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, -6);\n}\nEND_TEST\nSTART_TEST(test_prepare_math_failure9) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window  { width: -128;}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, -128);\n}\nEND_TEST\nSTART_TEST(test_prepare_default) {\n  rofi_theme_parse_string(\"@import \\\"default\\\"\");\n\n  ck_assert_ptr_null(error_msg);\n  ck_assert_ptr_nonnull(rofi_theme);\n}\nEND_TEST\nSTART_TEST(test_prepare_environment_nf) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window {  width: env(QER_TEST,128); }\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 128);\n}\nEND_TEST\nSTART_TEST(test_prepare_environment_f) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  setenv(\"QER_TEST\", \"64\", 1);\n  rofi_theme_parse_string(\"window {  width: env(QER_TEST,128); }\");\n  unsetenv(\"QER_TEST\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 64);\n}\nEND_TEST\nSTART_TEST(test_prepare_environment_old_style) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  setenv(\"QER_TEST\", \"64\", 1);\n  rofi_theme_parse_string(\"window {  width: ${QER_TEST}; }\");\n  rofi_theme_parse_process_conditionals();\n  unsetenv(\"QER_TEST\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 64);\n}\nEND_TEST\nSTART_TEST(test_prepare_environment_media_f) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  setenv(\"QER_TEST\", \"true\", 1);\n  rofi_theme_parse_string(\"window { width: 32; } @media( enabled: \"\n                          \"env(QER_TEST,false)){ window {width:64; }}\");\n  rofi_theme_parse_process_conditionals();\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  unsetenv(\"QER_TEST\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 64);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_environment_media_nf) {\n  widget wid;\n  wid.name = \"window\";\n  wid.state = \"\";\n  rofi_theme_parse_string(\"window { width: 32; } @media( enabled: \"\n                          \"env(QER_TEST,false)){ window {width:64; }}\");\n  ck_assert_ptr_nonnull(rofi_theme);\n  // ck_assert_ptr_null ( rofi_theme->widgets );\n  ck_assert_ptr_null(rofi_theme->properties);\n  ck_assert_ptr_null(rofi_theme->parent);\n  ck_assert_str_eq(rofi_theme->name, \"Root\");\n  RofiDistance l = rofi_theme_get_distance(&wid, \"width\", 0);\n  int dist = distance_get_pixel(l, ROFI_ORIENTATION_HORIZONTAL);\n  ck_assert_int_eq(dist, 32);\n}\nEND_TEST\n\nSTART_TEST(test_prepare_path) {\n  char *current_dir = g_get_current_dir();\n  ck_assert_ptr_nonnull(current_dir);\n  char *f = rofi_theme_parse_prepare_file(\"../\");\n  ck_assert_ptr_nonnull(f);\n  ck_assert_int_eq(*f, '/');\n  ck_assert_str_ne(f, current_dir);\n  ck_assert(g_str_has_prefix(current_dir, f) == TRUE);\n  g_free(f);\n\n  g_free(current_dir);\n}\nEND_TEST\n\nSTART_TEST(test_properties_types_names) {\n  ck_assert_str_eq(PropertyTypeName[P_INTEGER], \"Integer\");\n  ck_assert_str_eq(PropertyTypeName[P_DOUBLE], \"Double\");\n  ck_assert_str_eq(PropertyTypeName[P_STRING], \"String\");\n  ck_assert_str_eq(PropertyTypeName[P_BOOLEAN], \"Boolean\");\n  ck_assert_str_eq(PropertyTypeName[P_COLOR], \"Color\");\n  ck_assert_str_eq(PropertyTypeName[P_PADDING], \"Padding\");\n  ck_assert_str_eq(PropertyTypeName[P_LINK], \"Reference\");\n  ck_assert_str_eq(PropertyTypeName[P_POSITION], \"Position\");\n  ck_assert_str_eq(PropertyTypeName[P_HIGHLIGHT], \"Highlight\");\n  ck_assert_str_eq(PropertyTypeName[P_LIST], \"List\");\n  ck_assert_str_eq(PropertyTypeName[P_ORIENTATION], \"Orientation\");\n}\nEND_TEST\n\nstatic Suite *theme_parser_suite(void) {\n  Suite *s;\n\n  s = suite_create(\"Theme\");\n\n  /* Core test case */\n  {\n    TCase *tc_core = tcase_create(\"Core\");\n    tcase_add_checked_fixture(tc_core, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_core, test_properties_types_names);\n    tcase_add_test(tc_core, test_core_empty_string);\n    tcase_add_test(tc_core, test_core_empty_global_section);\n    tcase_add_test(tc_core, test_core_empty_section);\n    tcase_add_test(tc_core, test_core_error_root);\n    tcase_add_test(tc_core, test_core_comments);\n    tcase_add_test(tc_core, test_core_newline);\n    tcase_add_test(tc_core, test_core_properties_error);\n    suite_add_tcase(s, tc_core);\n  }\n  {\n    TCase *tc_prop_bool = tcase_create(\"PropertiesBoolean\");\n    tcase_add_checked_fixture(tc_prop_bool, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_bool, test_properties_boolean);\n    tcase_add_test(tc_prop_bool, test_properties_boolean_reference);\n    suite_add_tcase(s, tc_prop_bool);\n  }\n  {\n    TCase *tc_prop_distance = tcase_create(\"PropertiesDistance\");\n    tcase_add_checked_fixture(tc_prop_distance, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_distance, test_properties_distance_em);\n    tcase_add_test(tc_prop_distance, test_properties_distance_ch);\n    tcase_add_test(tc_prop_distance, test_properties_distance_px);\n    tcase_add_test(tc_prop_distance, test_properties_distance_percent);\n    tcase_add_test(tc_prop_distance, test_properties_distance_em_linestyle);\n    tcase_add_test(tc_prop_distance, test_properties_distance_ch_linestyle);\n    tcase_add_test(tc_prop_distance, test_properties_distance_px_linestyle);\n\n    tcase_add_test(tc_prop_distance, test_properties_distance_mm);\n    tcase_add_test(tc_prop_distance, test_properties_distance_mm_linestyle);\n    tcase_add_test(tc_prop_distance,\n                   test_properties_distance_percent_linestyle);\n    suite_add_tcase(s, tc_prop_distance);\n  }\n  {\n    TCase *tc_prop_position = tcase_create(\"PropertiesPosition\");\n    tcase_add_checked_fixture(tc_prop_position, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_position, test_properties_position);\n    suite_add_tcase(s, tc_prop_position);\n  }\n  {\n    TCase *tc_prop_style = tcase_create(\"PropertiesStyle\");\n    tcase_add_checked_fixture(tc_prop_style, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_style, test_properties_style);\n    tcase_add_test(tc_prop_style, test_properties_style2);\n    tcase_add_test(tc_prop_style, test_properties_style_color);\n    suite_add_tcase(s, tc_prop_style);\n  }\n  {\n    TCase *tc_prop_color = tcase_create(\"PropertiesColor\");\n    tcase_add_checked_fixture(tc_prop_color, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_color, test_properties_color_h3);\n    tcase_add_test(tc_prop_color, test_properties_color_h4);\n    tcase_add_test(tc_prop_color, test_properties_color_h6);\n    tcase_add_test(tc_prop_color, test_properties_color_h8);\n    tcase_add_test(tc_prop_color, test_properties_color_rgb);\n    tcase_add_test(tc_prop_color, test_properties_color_rgba);\n    tcase_add_test(tc_prop_color, test_properties_color_rgba_percent);\n    tcase_add_test(tc_prop_color, test_properties_color_rgb_p);\n    tcase_add_test(tc_prop_color, test_properties_color_rgba_p);\n    tcase_add_test(tc_prop_color, test_properties_color_rgba_percent_p);\n    tcase_add_test(tc_prop_color, test_properties_color_argb);\n    tcase_add_test(tc_prop_color, test_properties_color_hsl);\n    tcase_add_test(tc_prop_color, test_properties_color_hsla);\n    tcase_add_test(tc_prop_color, test_properties_color_hsl_ws);\n    tcase_add_test(tc_prop_color, test_properties_color_hsla_ws);\n    tcase_add_test(tc_prop_color, test_properties_color_hwb);\n    tcase_add_test(tc_prop_color, test_properties_color_hwb_ws);\n    tcase_add_test(tc_prop_color, test_properties_color_cmyk);\n    tcase_add_test(tc_prop_color, test_properties_color_cmyk_ws);\n    tcase_add_test(tc_prop_color, test_properties_color_names);\n    tcase_add_test(tc_prop_color, test_properties_color_names_alpha);\n    suite_add_tcase(s, tc_prop_color);\n  }\n  {\n    TCase *tc_prop_padding = tcase_create(\"PropertiesPadding\");\n    tcase_add_checked_fixture(tc_prop_padding, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_padding, test_properties_padding_2);\n    tcase_add_test(tc_prop_padding, test_properties_padding_3);\n    tcase_add_test(tc_prop_padding, test_properties_padding_4);\n    suite_add_tcase(s, tc_prop_padding);\n  }\n  {\n    TCase *tc_prop_string = tcase_create(\"PropertiesString\");\n    tcase_add_checked_fixture(tc_prop_string, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_string, test_properties_string);\n    tcase_add_test(tc_prop_string, test_properties_string_escape);\n    suite_add_tcase(s, tc_prop_string);\n  }\n\n  {\n    TCase *tc_prop_double = tcase_create(\"PropertiesDouble\");\n    tcase_add_checked_fixture(tc_prop_double, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_double, test_properties_double);\n    suite_add_tcase(s, tc_prop_double);\n  }\n  {\n    TCase *tc_prop_integer = tcase_create(\"PropertiesInteger\");\n    tcase_add_checked_fixture(tc_prop_integer, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_integer, test_properties_integer);\n    suite_add_tcase(s, tc_prop_integer);\n  }\n  {\n    TCase *tc_prop_orientation = tcase_create(\"Propertiesorientation\");\n    tcase_add_checked_fixture(tc_prop_orientation, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_orientation, test_properties_orientation);\n    tcase_add_test(tc_prop_orientation, test_properties_orientation_case);\n    suite_add_tcase(s, tc_prop_orientation);\n  }\n  {\n    TCase *tc_prop_cursor = tcase_create(\"Propertiescursor\");\n    tcase_add_checked_fixture(tc_prop_cursor, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_cursor, test_properties_cursor);\n    tcase_add_test(tc_prop_cursor, test_properties_cursor_case);\n    suite_add_tcase(s, tc_prop_cursor);\n  }\n  {\n    TCase *tc_prop_configuration = tcase_create(\"Configuration\");\n    tcase_add_checked_fixture(tc_prop_configuration, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_configuration, test_configuration);\n    suite_add_tcase(s, tc_prop_configuration);\n  }\n  {\n    TCase *tc_prop_list = tcase_create(\"Propertieslist\");\n    tcase_add_checked_fixture(tc_prop_list, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_list, test_properties_list);\n    suite_add_tcase(s, tc_prop_list);\n  }\n  {\n    TCase *tc_prop_parse_file = tcase_create(\"ParseFile\");\n    tcase_add_checked_fixture(tc_prop_parse_file, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_parse_file, test_parse_file_empty);\n    tcase_add_test(tc_prop_parse_file, test_parse_file_not_existing);\n    suite_add_tcase(s, tc_prop_parse_file);\n  }\n  {\n    TCase *tc_prop_import = tcase_create(\"Import\");\n    tcase_add_checked_fixture(tc_prop_import, theme_parser_setup,\n                              theme_parser_teardown);\n    tcase_add_test(tc_prop_import, test_import_empty);\n    tcase_add_test(tc_prop_import, test_import_error);\n    suite_add_tcase(s, tc_prop_import);\n  }\n  {\n    TCase *tc_prepare_path = tcase_create(\"prepare_path\");\n    tcase_add_test(tc_prepare_path, test_prepare_path);\n    suite_add_tcase(s, tc_prepare_path);\n  }\n  {\n    TCase *tc_prepare_array = tcase_create(\"array\");\n    tcase_add_test(tc_prepare_array, test_prepare_array);\n    suite_add_tcase(s, tc_prepare_array);\n  }\n  {\n    TCase *tc_prepare_default = tcase_create(\"default\");\n    tcase_add_test(tc_prepare_default, test_prepare_default);\n    suite_add_tcase(s, tc_prepare_default);\n  }\n  {\n    TCase *tc_prepare_math = tcase_create(\"math\");\n    tcase_add_test(tc_prepare_math, test_prepare_math_add);\n    tcase_add_test(tc_prepare_math, test_prepare_math_subtract);\n    tcase_add_test(tc_prepare_math, test_prepare_math_multiply);\n    tcase_add_test(tc_prepare_math, test_prepare_math_modulo);\n    tcase_add_test(tc_prepare_math, test_prepare_math_floor);\n    tcase_add_test(tc_prepare_math, test_prepare_math_ceil);\n    tcase_add_test(tc_prepare_math, test_prepare_math_round);\n    tcase_add_test(tc_prepare_math, test_prepare_math_min);\n    tcase_add_test(tc_prepare_math, test_prepare_math_max);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure2);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure3);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure4);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure5);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure6);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure7);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure8);\n    tcase_add_test(tc_prepare_math, test_prepare_math_failure9);\n    suite_add_tcase(s, tc_prepare_math);\n  }\n  {\n    TCase *tc_prepare_default = tcase_create(\"environment\");\n    tcase_add_test(tc_prepare_default, test_prepare_environment_nf);\n    tcase_add_test(tc_prepare_default, test_prepare_environment_f);\n    tcase_add_test(tc_prepare_default, test_prepare_environment_old_style);\n    tcase_add_test(tc_prepare_default, test_prepare_environment_media_f);\n    tcase_add_test(tc_prepare_default, test_prepare_environment_media_nf);\n    suite_add_tcase(s, tc_prepare_default);\n  }\n  return s;\n}\n\nint main(int argc, char **argv) {\n  cmd_set_arguments(argc, argv);\n\n  if (setlocale(LC_ALL, \"C\") == NULL) {\n    fprintf(stderr, \"Failed to set locale.\\n\");\n    return EXIT_FAILURE;\n  }\n\n  Suite *s;\n  SRunner *sr;\n\n  s = theme_parser_suite();\n  sr = srunner_create(s);\n\n  srunner_run_all(sr, CK_NORMAL);\n  int number_failed = srunner_ntests_failed(sr);\n  srunner_free(sr);\n\n  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/widget-test.c",
    "content": "/*\n * rofi\n *\n * MIT/X11 License\n * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n */\n\n#include \"display.h\"\n#include \"glibconfig.h\"\n#include \"rofi-icon-fetcher.h\"\n#include \"rofi.h\"\n#include \"xrmoptions.h\"\n#include <assert.h>\n#include <glib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <widgets/widget-internal.h>\n#include <widgets/widget.h>\nunsigned int test = 0;\nint rofi_is_in_dmenu_mode = 0;\n#define TASSERT(a)                                                             \\\n  {                                                                            \\\n    assert(a);                                                                 \\\n    printf(\"Test %3u passed (%s)\\n\", ++test, #a);                              \\\n  }\n\nThemeWidget *rofi_configuration = NULL;\n\nuint32_t rofi_icon_fetcher_query(G_GNUC_UNUSED const char *name,\n                                 G_GNUC_UNUSED const int size) {\n  return 0;\n}\nuint32_t rofi_icon_fetcher_query_advanced(G_GNUC_UNUSED const char *name,\n                                          G_GNUC_UNUSED const int wsize,\n                                          G_GNUC_UNUSED const int hsize) {\n  return 0;\n}\nvoid rofi_timings_tick(G_GNUC_UNUSED const char *file,\n                       G_GNUC_UNUSED char const *str, G_GNUC_UNUSED int line,\n                       G_GNUC_UNUSED char const *msg);\nvoid rofi_timings_tick(G_GNUC_UNUSED const char *file,\n                       G_GNUC_UNUSED char const *str, G_GNUC_UNUSED int line,\n                       G_GNUC_UNUSED char const *msg) {}\n\ncairo_surface_t *rofi_icon_fetcher_get(G_GNUC_UNUSED const uint32_t uid) {\n  return NULL;\n}\n\ngboolean config_parse_set_property(G_GNUC_UNUSED const Property *p,\n                                   G_GNUC_UNUSED char **error) {\n  return FALSE;\n}\nvoid rofi_add_error_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_add_warning_message(G_GNUC_UNUSED GString *msg) {}\nvoid rofi_view_queue_redraw(void) {}\nint monitor_active(G_GNUC_UNUSED workarea *mon) { return 0; }\nvoid rofi_view_get_current_monitor(G_GNUC_UNUSED int *width,\n                                   G_GNUC_UNUSED int *height) {}\nint rofi_view_error_dialog(const char *msg, G_GNUC_UNUSED int markup) {\n  fputs(msg, stderr);\n  return FALSE;\n}\n\nvoid display_startup_notification(\n    G_GNUC_UNUSED RofiHelperExecuteContext *context,\n    G_GNUC_UNUSED GSpawnChildSetupFunc *child_setup,\n    G_GNUC_UNUSED gpointer *user_data) {}\n\nint main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) {\n  //    box 20 by 40\n  widget *wid = (widget *)g_malloc0(sizeof(widget));\n  widget_resize(wid, 20, 40);\n  widget_move(wid, 10, 10);\n  // Getter, setter x pos\n  //\n  TASSERT(widget_get_x_pos(wid) == 10);\n  TASSERT(widget_get_y_pos(wid) == 10);\n\n  // Left of box\n  TASSERT(widget_intersect(wid, 0, 0) == 0);\n  TASSERT(widget_intersect(wid, 0, 10) == 0);\n  TASSERT(widget_intersect(wid, 0, 25) == 0);\n  TASSERT(widget_intersect(wid, 0, 40) == 0);\n  TASSERT(widget_intersect(wid, 0, 50) == 0);\n  TASSERT(widget_intersect(wid, 9, 0) == 0);\n  TASSERT(widget_intersect(wid, 9, 10) == 0);\n  TASSERT(widget_intersect(wid, 9, 25) == 0);\n  TASSERT(widget_intersect(wid, 9, 40) == 0);\n  TASSERT(widget_intersect(wid, 9, 50) == 0);\n  TASSERT(widget_intersect(wid, 10, 0) == 0);\n  TASSERT(widget_intersect(wid, 10, 10) == 1);\n  TASSERT(widget_intersect(wid, 10, 25) == 1);\n  TASSERT(widget_intersect(wid, 10, 40) == 1);\n  TASSERT(widget_intersect(wid, 10, 50) == 0);\n\n  // Middle\n\n  TASSERT(widget_intersect(wid, 25, 0) == 0);\n  TASSERT(widget_intersect(wid, 25, 10) == 1);\n  TASSERT(widget_intersect(wid, 25, 25) == 1);\n  TASSERT(widget_intersect(wid, 25, 40) == 1);\n  TASSERT(widget_intersect(wid, 25, 50) == 0);\n\n  // Right\n  TASSERT(widget_intersect(wid, 29, 0) == 0);\n  TASSERT(widget_intersect(wid, 29, 10) == 1);\n  TASSERT(widget_intersect(wid, 29, 25) == 1);\n  TASSERT(widget_intersect(wid, 29, 40) == 1);\n  TASSERT(widget_intersect(wid, 29, 50) == 0);\n\n  TASSERT(widget_intersect(wid, 30, 0) == 0);\n  TASSERT(widget_intersect(wid, 30, 10) == 0);\n  TASSERT(widget_intersect(wid, 30, 25) == 0);\n  TASSERT(widget_intersect(wid, 30, 40) == 0);\n  TASSERT(widget_intersect(wid, 30, 50) == 0);\n\n  widget_move(wid, 30, 30);\n  // Left of box\n  TASSERT(widget_intersect(wid, 10, 20) == 0);\n  TASSERT(widget_intersect(wid, 10, 30) == 0);\n  TASSERT(widget_intersect(wid, 10, 45) == 0);\n  TASSERT(widget_intersect(wid, 10, 60) == 0);\n  TASSERT(widget_intersect(wid, 10, 70) == 0);\n  TASSERT(widget_intersect(wid, 19, 20) == 0);\n  TASSERT(widget_intersect(wid, 19, 30) == 0);\n  TASSERT(widget_intersect(wid, 19, 45) == 0);\n  TASSERT(widget_intersect(wid, 19, 60) == 0);\n  TASSERT(widget_intersect(wid, 19, 70) == 0);\n  TASSERT(widget_intersect(wid, 30, 20) == 0);\n  TASSERT(widget_intersect(wid, 30, 30) == 1);\n  TASSERT(widget_intersect(wid, 30, 45) == 1);\n  TASSERT(widget_intersect(wid, 30, 60) == 1);\n  TASSERT(widget_intersect(wid, 30, 70) == 0);\n\n  // Middle\n\n  TASSERT(widget_intersect(wid, 20 + 25, 20 + 0) == 0);\n  TASSERT(widget_intersect(wid, 20 + 25, 20 + 10) == 1);\n  TASSERT(widget_intersect(wid, 20 + 25, 20 + 25) == 1);\n  TASSERT(widget_intersect(wid, 20 + 25, 20 + 40) == 1);\n  TASSERT(widget_intersect(wid, 20 + 25, 20 + 50) == 0);\n\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 0) == 0);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 10) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 25) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 40) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 50) == 0);\n\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 0) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 10) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 25) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 40) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 50) == 0);\n\n  // Right\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 0) == 0);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 10) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 25) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 40) == 1);\n  TASSERT(widget_intersect(wid, 20 + 29, 20 + 50) == 0);\n\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 0) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 10) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 25) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 40) == 0);\n  TASSERT(widget_intersect(wid, 20 + 30, 20 + 50) == 0);\n\n  TASSERT(widget_intersect(wid, -100, -100) == 0);\n  TASSERT(widget_intersect(wid, INT_MIN, INT_MIN) == 0);\n  TASSERT(widget_intersect(wid, INT_MAX, INT_MAX) == 0);\n\n  // Other wrappers.\n  TASSERT(widget_get_height(wid) == wid->h);\n  TASSERT(widget_get_width(wid) == wid->w);\n\n  TASSERT(widget_enabled(wid) == FALSE);\n  widget_enable(wid);\n  TASSERT(widget_enabled(wid) == TRUE);\n  widget_disable(wid);\n  TASSERT(widget_enabled(wid) == FALSE);\n  // Null pointer tests.\n  TASSERT(widget_intersect(NULL, 0, 0) == 0);\n  widget_move(NULL, 0, 0);\n  TASSERT(widget_get_height(NULL) == 0);\n  TASSERT(widget_get_width(NULL) == 0);\n  TASSERT(widget_enabled(NULL) == 0);\n  widget_disable(NULL);\n  widget_enable(NULL);\n  widget_draw(NULL, NULL);\n  widget_free(NULL);\n  widget_resize(NULL, 0, 0);\n  widget_update(NULL);\n  widget_queue_redraw(NULL);\n  TASSERT(widget_need_redraw(NULL) == FALSE);\n  widget_trigger_action(NULL, 0, 0, 0);\n  widget_set_trigger_action_handler(NULL, NULL, NULL);\n\n  g_free(wid);\n}\n"
  },
  {
    "path": "themes/Adapta-Nokto.rasi",
    "content": "/*******************************************************************************\n * ROFI Color theme\n * Based on Adapta-Nokto GTK theme (https://github.com/adapta-project/adapta-gtk-theme)\n * User: PyGeek03\n * Copyright: PyGeek03\n ********************************************************************************/\n\n* {\n    selected-normal-foreground:  rgba ( 250, 251, 252, 100 % );\n    foreground:                  rgba ( 250, 251, 252, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 69, 90, 100, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 253, 246, 227, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 82, 82, 100 % );\n    alternate-urgent-background: rgba ( 69, 90, 100, 100 % );\n    active-foreground:           rgba ( 0, 188, 212, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 253, 246, 227, 100 % );\n    alternate-active-background: rgba ( 69, 90, 100, 100 % );\n    background:                  rgba ( 58, 76, 84, 100 % );\n    bordercolor:                 rgba ( 42, 55, 62, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 69, 90, 100, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 0, 188, 212, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 195, 198, 200, 100 % );\n    urgent-background:           rgba ( 69, 90, 100, 100 % );\n    selected-urgent-background:  rgba ( 255, 82, 82, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 69, 90, 100, 100 % );\n    selected-active-background:  rgba ( 0, 150, 136, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\n\nelement normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/Arc-Dark.rasi",
    "content": "/************************************************\n * ROFI Color theme\n * User: leofa\n * Copyright: 2017 leofa\n ***********************************************/\n\n* {\n    selected-normal-foreground:  rgba ( 249, 249, 249, 100 % );\n    foreground:                  rgba ( 196, 203, 212, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 64, 69, 82, 59 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 249, 249, 249, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 204, 102, 102, 100 % );\n    alternate-urgent-background: rgba ( 75, 81, 96, 90 % );\n    active-foreground:           rgba ( 101, 172, 255, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 249, 249, 249, 100 % );\n    alternate-active-background: rgba ( 75, 81, 96, 89 % );\n    background:                  rgba ( 45, 48, 59, 95 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           @background;\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 64, 132, 214, 100 % );\n    border-color:                rgba ( 124, 131, 137, 100 % );\n    spacing:                     2;\n    separatorcolor:              rgba ( 29, 31, 33, 100 % );\n    urgent-background:           rgba ( 29, 31, 33, 17 % );\n    selected-urgent-background:  rgba ( 165, 66, 66, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 29, 31, 33, 17 % );\n    selected-active-background:  rgba ( 68, 145, 237, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-color: @normal-foreground;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/Arc.rasi",
    "content": "/*******************************************************************************\n * ROFI Color theme\n * User: Sergio Morales\n * Copyright: Sergio Morales\n *******************************************************************************/\n\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 82, 93, 118, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 245, 245, 245, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 220, 50, 47, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 220, 50, 47, 100 % );\n    alternate-urgent-background: rgba ( 245, 245, 245, 100 % );\n    active-foreground:           rgba ( 194, 202, 208, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 194, 202, 208, 100 % );\n    alternate-active-background: rgba ( 245, 245, 245, 100 % );\n    background:                  rgba ( 255, 255, 255, 100 % );\n    bordercolor:                 rgba ( 245, 245, 245, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 255, 255, 255, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 82, 148, 226, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              @foreground;\n    urgent-background:           rgba ( 255, 255, 255, 100 % );\n    selected-urgent-background:  rgba ( 82, 148, 226, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 255, 255, 255, 100 % );\n    selected-active-background:  rgba ( 82, 148, 226, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/DarkBlue.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    selected-normal-foreground:  rgba ( 2, 20, 63, 100 % );\n    foreground:                  rgba ( 219, 223, 188, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 0, 0, 0, 0 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 2, 20, 63, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 129, 255, 100 % );\n    alternate-urgent-background: rgba ( 0, 0, 0, 0 % );\n    active-foreground:           rgba ( 138, 196, 255, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 2, 20, 63, 100 % );\n    alternate-active-background: rgba ( 0, 0, 0, 0 % );\n    background:                  rgba ( 0, 0, 33, 87 % );\n    bordercolor:                 rgba ( 219, 223, 188, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 0, 208, 0 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 219, 223, 188, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 219, 223, 188, 100 % );\n    urgent-background:           rgba ( 0, 0, 208, 0 % );\n    selected-urgent-background:  rgba ( 255, 129, 127, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 0, 208, 0 % );\n    selected-active-background:  rgba ( 138, 196, 255, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt, button{\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/Indego.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    selected-normal-foreground:  rgba ( 232, 234, 246, 100 % );\n    foreground:                  rgba ( 232, 234, 246, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 40, 53, 147, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 183, 28, 28, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 205, 210, 100 % );\n    alternate-urgent-background: rgba ( 183, 28, 28, 100 % );\n    active-foreground:           rgba ( 178, 235, 242, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 0, 96, 100, 100 % );\n    alternate-active-background: rgba ( 0, 96, 100, 100 % );\n    background:                  rgba ( 26, 35, 126, 100 % );\n    bordercolor:                 rgba ( 232, 234, 246, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 152, 108, 128, 3 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 63, 81, 181, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 232, 234, 246, 100 % );\n    urgent-background:           rgba ( 223, 110, 0, 6 % );\n    selected-urgent-background:  rgba ( 255, 205, 210, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 223, 110, 0, 6 % );\n    selected-active-background:  rgba ( 178, 235, 242, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/Monokai.rasi",
    "content": "/**\n * ROFI Color theme\n * User: milouse\n * Copyright: Étienne Deparis\n */\n\n* {\n    selected-normal-foreground:  rgba ( 248, 248, 242, 100 % );\n    foreground:                  rgba ( 248, 248, 242, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 39, 40, 34, 0 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 248, 248, 242, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 249, 38, 114, 100 % );\n    alternate-urgent-background: rgba ( 39, 40, 34, 0 % );\n    active-foreground:           rgba ( 166, 226, 42, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 166, 226, 42, 100 % );\n    alternate-active-background: rgba ( 39, 40, 34, 0 % );\n    background:                  rgba ( 39, 40, 34, 93 % );\n    bordercolor:                 rgba ( 0, 43, 54, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 39, 40, 34, 0 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 20, 20, 17, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 230, 219, 116, 100 % );\n    urgent-background:           rgba ( 39, 40, 34, 0 % );\n    selected-urgent-background:  rgba ( 249, 38, 114, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 39, 40, 34, 0 % );\n    selected-active-background:  rgba ( 20, 20, 17, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/Paper.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    selected-normal-foreground:  rgba ( 245, 245, 245, 100 % );\n    foreground:                  rgba ( 0, 43, 54, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 208, 208, 208, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 245, 245, 245, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 215, 95, 0, 100 % );\n    alternate-urgent-background: rgba ( 208, 208, 208, 100 % );\n    active-foreground:           rgba ( 0, 95, 135, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 245, 245, 245, 100 % );\n    alternate-active-background: rgba ( 208, 208, 208, 100 % );\n    background:                  rgba ( 245, 245, 245, 100 % );\n    bordercolor:                 rgba ( 68, 68, 68, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 95, 95, 32, 6 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 66, 113, 174, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 68, 68, 68, 100 % );\n    urgent-background:           rgba ( 245, 245, 245, 100 % );\n    selected-urgent-background:  rgba ( 215, 95, 0, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 245, 245, 245, 100 % );\n    selected-active-background:  rgba ( 0, 95, 135, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/android_notification.rasi",
    "content": "/*******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n *******************************************************************************/\n\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 193, 193, 193, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 39, 50, 56, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 255, 24, 68, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 24, 68, 100 % );\n    alternate-urgent-background: rgba ( 39, 50, 56, 100 % );\n    active-foreground:           rgba ( 128, 203, 196, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 128, 203, 196, 100 % );\n    alternate-active-background: rgba ( 39, 50, 56, 100 % );\n    background:                  rgba ( 39, 50, 56, 100 % );\n    bordercolor:                 rgba ( 39, 50, 56, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 39, 50, 56, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 57, 66, 73, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 30, 37, 41, 100 % );\n    urgent-background:           rgba ( 39, 50, 56, 100 % );\n    selected-urgent-background:  rgba ( 57, 66, 73, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 39, 50, 56, 100 % );\n    selected-active-background:  rgba ( 57, 66, 73, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/arthur.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    foreground:  #ffeedd;\n    backlight:   #ccffeedd;\n    background-color:  transparent;\n    dark: #1c1c1c;\n    // Black\n    black:       #3d352a;\n    lightblack:  #554444;\n    tlightblack:  #554444cc;\n    //\n    // Red\n    red:         #cd5c5c;\n    lightred:    #cc5533;\n    //\n    // Green\n    green:       #86af80;\n    lightgreen:  #88cc22;\n    //\n    // Yellow\n    yellow:      #e8ae5b;\n    lightyellow:     #ffa75d;\n    //\n    // Blue\n    blue:      #6495ed;\n    lightblue:     #87ceeb;\n    //\n    // Magenta\n    magenta:      #deb887;\n    lightmagenta:     #996600;\n    //\n    // Cyan\n    cyan:      #b0c4de;\n    tcyan:      #ccb0c4de;\n    lightcyan:     #b0c4de;\n    //\n    // White\n    white:      #bbaa99;\n    lightwhite:     #ddccbb;\n    //\n    // Bold, Italic, Underline\n    highlight:     underline bold #ffffff;\n\n    transparent: rgba(0,0,0,0);\n    font: \"Source Code Pro 10\";\n}\nwindow {\n    location: center;\n    anchor:   center;\n    transparency: \"real\";\n    padding: 10px;\n    border:  0px;\n    border-radius: 10px;\n    color: @magenta;\n    background-color: @transparent;\n    spacing: 0;\n    children:  [mainbox];\n    orientation: horizontal;\n}\nmainbox {\n    spacing: 0;\n    children: [ inputbar, message, listview ];\n}\nmessage {\n    border-color: @foreground;\n    border:  0px 2px 2px 2px;\n//    border-radius: 10px;\n    padding: 5;\n    background-color: @tcyan;\n}\nmessage {\n    font: \"Source Code Pro 8\";\n    color: @black;\n}\ninputbar {\n    color: @lightgreen;\n    padding: 11px;\n    background-color: @tlightblack;\n    border: 2px 2px 2px 2px;\n    border-radius:  15px 15px 0px 0px;\n    border-color: @foreground;\n    font: \"Source Code Pro 18\";\n}\nentry,prompt,case-indicator {\n    text-font: inherit;\n    text-color:inherit;\n}\nprompt {\n    margin:     0px 0.3em 0em 0em ;\n}\nlistview {\n    padding: 8px;\n    border-radius: 0px 0px 15px 15px;\n    border-color: @foreground;\n    border: 0px 2px 2px 2px;\n    background-color: #1c1c1ccc;\n    dynamic: false;\n    lines: 10;\n}\nelement {\n    padding: 3px;\n    vertical-align: 0.5;\n//    border: 2px;\n    border-radius: 4px;\n    background-color: transparent;\n    color: @foreground;\n    font:inherit;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement selected.normal {\n    background-color: @blue;\n}\nelement normal active {\n    foreground: @lightblue;\n}\nelement normal urgent {\n    foreground: @lightred;\n}\nelement alternate normal {\n}\nelement alternate active {\n    foreground: @lightblue;\n}\nelement alternate urgent {\n    foreground: @lightred;\n}\nelement selected active {\n    background-color: @lightblue;\n    foreground: @dark;\n}\nelement selected urgent {\n    background-color: @lightred;\n    foreground: @dark;\n}\nelement normal normal {\n\n}\nvertb {\n    expand: false;\n    children: [ dummy0, mode-switcher, dummy1  ];\n}\ndummy0,  dummy1 {\n    expand: true;\n}\nmode-switcher {\n    expand: false;\n    orientation: vertical;\n    spacing: 0px;\n    border: 0px 0px 0px 0px;\n}\nbutton {\n    font: \"FontAwesome 22\";\n    padding: 6px;\n    border: 2px 0px 2px 2px;\n    border-radius: 4px 0px 0px 4px;\n    background-color: @tlightblack;\n    border-color: @foreground;\n    color: @foreground;\n    horizontal-align: 0.5;\n}\nbutton selected normal {\n    color: @dark;\n    border: 2px 0px 2px 2px;\n    background-color: @backlight;\n    border-color: @foreground;\n}\nerror-message {\n    expand: true;\n    background-color: red;\n    border-color: darkred;\n    border: 2px;\n    padding: 1em;\n}\n"
  },
  {
    "path": "themes/blue.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    selected-normal-foreground:  rgba ( 0, 96, 160, 100 % );\n    foreground:                  rgba ( 0, 176, 239, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 0, 0, 0, 0 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 0, 96, 160, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 160, 160, 100 % );\n    alternate-urgent-background: rgba ( 0, 0, 0, 0 % );\n    active-foreground:           rgba ( 160, 255, 160, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 0, 96, 160, 100 % );\n    alternate-active-background: rgba ( 0, 0, 0, 0 % );\n    background:                  rgba ( 0, 96, 160, 93 % );\n    bordercolor:                 rgba ( 0, 176, 239, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 0, 0, 0 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 0, 176, 239, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 0, 176, 239, 100 % );\n    urgent-background:           rgba ( 0, 0, 0, 0 % );\n    selected-urgent-background:  rgba ( 255, 160, 160, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 0, 0, 0 % );\n    selected-active-background:  rgba ( 160, 255, 160, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/breaking-themes/2076.rasi",
    "content": "/**\n * rofi -dump-theme output.\n * Rofi version: 1.7.7\n **/\n* {\n    text-color:                  var(urgent-background);\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-active-foreground:  var(background);\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    separatorcolor:              var(foreground);\n    urgent-foreground:           rgba ( 255, 178, 186, 100 % );\n    alternate-urgent-background: var(lightbg);\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    background-color:            var(active-background);\n    border-color:                var(foreground);\n    normal-background:           rgba ( 44, 21, 24, 100 % );\n    selected-urgent-background:  var(red);\n    alternate-active-background: var(lightbg);\n    spacing:                     2;\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    alternate-normal-foreground: var(foreground);\n    urgent-background:           rgba ( 44, 21, 24, 100 % );\n    selected-normal-foreground:  var(lightbg);\n    active-foreground:           rgba ( 255, 178, 186, 100 % );\n    background:                  rgba ( 253, 246, 227, 100 % );\n    font:                        \"JetBrainsMono Bold 10\";\n    selected-active-background:  var(blue);\n    active-background:           rgba ( 114, 51, 60, 100 % );\n    selected-normal-background:  var(lightfg);\n    alternate-normal-background: var(lightbg);\n    foreground:                  rgba ( 0, 43, 54, 100 % );\n    selected-urgent-foreground:  var(background);\n    normal-foreground:           rgba ( 255, 178, 186, 100 % );\n    alternate-urgent-foreground: var(red);\n    alternate-active-foreground: var(blue);\n}\nelement {\n    cursor:           pointer;\n    text-color:       inherit;\n    padding:          5px ;\n    children:         [ \"element-icon\",\"element-text\" ];\n    background-color: inherit;\n    border-radius:    5px ;\n    border-color:     var(active-background);\n    border:           5px ;\n    spacing:          5px ;\n    background:       transparent;\n}\nelement normal.normal {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement normal.urgent {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement normal.active {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement selected.normal {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    text-color:       var(urgent-background);\n}\nelement selected.urgent {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    text-color:       var(urgent-background);\n}\nelement selected.active {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    text-color:       var(urgent-background);\n}\nelement alternate.normal {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement alternate.urgent {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement alternate.active {\n    background-color: var(active-background);\n    text-color:       var(urgent-background);\n}\nelement-text {\n    background-color: var(active-background);\n    cursor:           pointer;\n    highlight:        inherit;\n    font:             \"JetBrains Mono Medium\";\n    text-color:       White;\n}\nelement-text selected.normal {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    font:             \"JetBrains Mono Medium\";\n    text-color:       var(active-background);\n}\nelement-text selected.urgent {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    font:             \"JetBrains Mono Medium\";\n    text-color:       var(active-background);\n}\nelement-text selected.active {\n    background-color: var(urgent-background);\n    border-color:     var(urgent-background);\n    font:             \"JetBrains Mono Medium\";\n    text-color:       var(active-background);\n}\nelement-icon {\n    background-color: inherit;\n    size:             1.0000em ;\n    cursor:           pointer;\n    text-color:       inherit;\n}\nwindow {\n    padding:          1.0000em ;\n    background-color: var(active-background);\n    border-color:     var(active-background);\n    border:           5px ;\n    border-radius:    10px ;\n}\nmainbox {\n    padding:  0;\n    spacing:  0px ;\n    border:   0;\n    children: [ \"message\",\"inputbar\",\"listview\" ];\n}\nmessage {\n    enabled:          true;\n    text-color:       inherit;\n    padding:          0.5000em ;\n    size:             400.0000em ;\n    lines:            8;\n    background-color: var(active-background);\n    margin:           0px 100px ;\n    border-color:     var(active-background);\n    border:           5px ;\n    border-radius:    10px ;\n    columns:          1;\n}\ntextbox {\n    text-color:        inherit;\n    markup:            true;\n    blink:             true;\n    size:              400.0000em ;\n    background-color:  inherit;\n    placeholder-color: inherit;\n    vertical-align:    0.50;\n    horizontal-align:  0.50;\n    font:              \"JetBrainsMono Bold 15\";\n}\nlistview {\n    fixed-height:     0;\n    padding:          0.5000em ;\n    scrollbar:        true;\n    lines:            8;\n    background-color: var(active-background);\n    border-radius:    10px ;\n    border-color:     var(active-background);\n    border:           0px 5px 5px ;\n    spacing:          10px ;\n    columns:          1;\n}\nscrollbar {\n    width:        4px ;\n    padding:      0;\n    handle-width: 8px ;\n    border:       0;\n    handle-color: var(urgent-background);\n}\nsidebar {\n    border-color: var(separatorcolor);\n    border:       2px dash 0px 0px ;\n}\nbutton {\n    cursor:           pointer;\n    text-color:       var(urgent-background);\n    background-color: var(active-background);\n    border-radius:    10px 10px 0px 0px ;\n    border-color:     var(active-background);\n    border:           0px 0px 5px ;\n    horizontal-align: 0.50;\n    spacing:          0;\n}\nbutton selected {\n    background-color: var(selected-normal-background);\n    text-color:       var(selected-normal-foreground);\n}\nbutton selected.normal {\n    padding:          0px ;\n    margin:           0px ;\n    background-color: var(active-foreground);\n    border-color:     var(active-background);\n    text-color:       var(urgent-background);\n    border:           5px ;\n    border-radius:    10px ;\n}\nnum-filtered-rows {\n    expand:     false;\n    text-color: Gray;\n}\nnum-rows {\n    expand:     false;\n    text-color: Gray;\n}\ntextbox-num-sep {\n    expand:     false;\n    str:        \"/\";\n    text-color: Gray;\n}\ninputbar {\n    text-color:       var(normal-foreground);\n    padding:          1px ;\n    children:         [ \"entry\",\"overlay\",\"case-indicator\" ];\n    margin:           0px 10px ;\n    background-color: var(active-background);\n    border-color:     var(active-background);\n    border:           5px ;\n    spacing:          0.4000em ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: var(normal-foreground);\n}\nentry {\n    text-color:        var(urgent-background);\n    cursor:            text;\n    border:            10px ;\n    background-color:  var(active-foreground);\n    border-radius:     2px ;\n    border-color:      var(active-foreground);\n    placeholder-color: var(active-background);\n    spacing:           0;\n    placeholder:       \"Search here\";\n}\nprompt {\n    spacing:    0;\n    text-color: var(normal-foreground);\n}\ntextbox-prompt-colon {\n    margin:     0px 0.3000em 0.0000em 0.0000em ;\n    expand:     false;\n    str:        \":\";\n    text-color: inherit;\n}\nerror-message {\n    padding:          12px ;\n    background-color: inherit;\n    border-color:     inherit;\n    border:           0px ;\n    border-radius:    0px ;\n    text-color:       inherit;\n}\nmode-switcher {\n    expand:  true;\n    spacing: 0px ;\n    border:  0px ;\n}\n"
  },
  {
    "path": "themes/breaking-themes/readme.md",
    "content": "Test themes that broke in the past.\n"
  },
  {
    "path": "themes/c64.rasi",
    "content": "/******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n ******************************************************************************/\n\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 79, 128, 255, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 0, 57, 255, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 255, 112, 71, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 112, 71, 100 % );\n    alternate-urgent-background: rgba ( 0, 57, 255, 100 % );\n    active-foreground:           rgba ( 104, 186, 80, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 104, 186, 80, 100 % );\n    alternate-active-background: rgba ( 0, 57, 255, 100 % );\n    background:                  rgba ( 0, 57, 255, 100 % );\n    bordercolor:                 rgba ( 0, 57, 255, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 57, 255, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 79, 128, 255, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 79, 128, 255, 100 % );\n    urgent-background:           rgba ( 0, 57, 255, 100 % );\n    selected-urgent-background:  rgba ( 79, 128, 255, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 57, 255, 100 % );\n    selected-active-background:  rgba ( 79, 128, 255, 100 % );\n}\nwindow {\n\tfont: \"Topaz-8 10\";\n    background-color: #4E7FFF;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n    margin: 40;\n    background-color: #003AFF;\n}\nmessage {\n    border:       1px dash 0px dash ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       0px 0px 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    false;\n    padding:      5px 5px 5px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        0px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/dmenu.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    background-color:      Black;\n    border-color:          White;\n    text-color:           White;\n    font:            \"Times New Roman 12\";\n}\nwindow {\n    anchor:     north;\n    location:   north;\n    width:      100%;\n    padding:    4px;\n    children:   [ horibox ];\n}\nhoribox {\n    orientation: horizontal;\n    children:   [ prompt, entry, listview ];\n}\nlistview {\n    layout:     horizontal;\n    spacing:    5px;\n    lines:      100;\n}\nentry {\n    expand:     false;\n    width:      10em;\n}\nelement {\n    padding: 0px 2px;\n}\nelement selected {\n    background-color: SteelBlue;\n}\n\nelement-text, element-icon {\n  background-color: inherit;\n  text-color: inherit;\n}\n"
  },
  {
    "path": "themes/docu.rasi",
    "content": "/**\n * ROFI Documentation theme.\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n/** Default settings, every widget inherits from this. */\n* {\n    /** Default background color is transparent. */\n    background-color: transparent;\n    /** Default text is white */\n    text-color:       white;\n}\n\n/**\n * Entry box on top. \n */\nentry {\n    /** top  and bottom border */\n    border: 2px 0px;\n    /** Dark grey border color */\n    border-color:  darkgrey;\n    /** Background is grey */\n    background-color: grey;\n    /** 4px padding on the inside of the border. */\n    padding:       4px;\n    /** when no text is set, show 'Type to filter' */\n    placeholder:       \"Type to filter\";\n    /** this text is dark grey */\n    placeholder-color: darkgrey;\n    /** inherit font setting from parent */\n    font: inherit;\n    cursor: text;\n}\n\n/**\n * Input bar\n */\ninputbar {\n    /** no spacing between widgets */\n    spacing: 0;\n    /** include entry and mode-switcher (removes prompt) */\n    children: [  icon-keyboard, entry, mode-switcher ];\n    /** use monospace font. */\n    font:   \"mono 18\";\n}\n\n/**\n * Mode switcher.\n *  We set it up to 'connect' to reset of input bar.\n */\nmode-switcher {\n    /** we use spacing between children to draw a 'border' */\n    spacing: 2px;\n    border: 2px;\n    border-radius: 0px 4px 4px 0px;\n    /** border and background are same color, widget will have desired bg color.*/\n    /** this way the spacing shows as a border */\n    border-color: darkgrey;\n    background-color: darkgrey;\n    /** inherit font setting from parent */\n    font: inherit;\n}\n\n/**\n * Buttons in mode switcher.\n */\nbutton {\n    background-color: grey;\n    border-color: darkgrey;\n    /** inherit font setting from parent */\n    font: inherit;\n    cursor: pointer;\n}\n\n/**\n * Selected buttons in mode switcher.\n */\nbutton selected {\n    background-color: lightgrey;\n    text-color:       black;\n}\n\n/**\n * Small icon in inputbar\n */\nicon-keyboard {\n    /** give it a 2 pixel border, except on the right side. */\n    border:        2px 0px 2px 2px;\n    /** with a radius on the left two corners. */ \n    border-radius: 4px 0px 0px 4px;\n    /** add matching border. */\n    border-color: darkgrey;\n    /** match background. */\n    background-color: grey;\n    /** move icon away from right border. */\n    padding: 0px 10px 0px 10px;\n    /** Only use required space. */\n    expand: false;\n    /** icon is around 1.2 font width */\n    size: 1.2em;\n    /** Icon name, we use symbolic name here */\n    filename: \"keyboard\";\n}\n\n/**\n * Main window widget\n */\nwindow {\n    /** Place on top center of rofi window on the top center of the screen. */\n    anchor: north;\n    location: north;\n\n    /** 100% screen width */\n    width:            100%;\n\n    /** Black transparent color. */\n    background-color: black / 70%;\n    /** Small one 1 font width border on inside of window. */\n    padding:           1em;\n\n    /** border */\n    border-color: black;\n    border:  0em 0.2em 0.2em;\n}\n\n/**\n * Main container in the window.\n */\nmainbox { \n    /** spacing between widgets */\n    spacing: 1em;\n}\n\n/**\n * listview that shows entries.\n */\nlistview {\n    /** 4 rows. */\n    lines: 4;\n    /** 6 columns */\n    columns: 6;\n    /** add 1 em spacing between items */\n    spacing: 1em;\n    /** Don't reduce columns if less items are available. */\n    fixed-columns: true;\n}\n/**\n * entry in listview.\n */\nelement {\n    /** clients are packed vertically. */\n    orientation:      vertical;\n    /** 2 px border */\n    border:           2px;\n    /** with 4px radius on corners. */\n    border-radius:    4px ;\n    border-color:     darkgrey;\n    background-color: grey;\n    /** 4 px padding on the inside of border */\n    cursor: pointer;\n    padding:          4px;\n}\n\n/** selected element */\nelement selected {\n    /** highlighted colors */\n    background-color: lightgrey;\n    text-color:       black;\n}\n\n/** Entry icon */\nelement-icon {\n    /** change size to 128 pixels. */\n    size: 128px;\n    cursor: inherit;\n}\n\n/** Entry text */\nelement-text {\n    /* align font in (horizontally) center */\n    horizontal-align: 0.5;\n    cursor: inherit;\n}\n"
  },
  {
    "path": "themes/fancy.rasi",
    "content": "/*******************************************************************************\n * ROFI Color theme\n * Theme designed to show off moving, packing of widgets, icons and more.\n * User: DaveDavenport\n * Copyright: DaveDavenport\n ********************************************************************************/\n* {\n    selected-normal-foreground:  rgba ( 248, 248, 242, 100 % );\n    foreground:                  rgba ( 248, 248, 242, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 39, 40, 34, 0 % );\n    selected-urgent-foreground:  rgba ( 248, 248, 242, 100 % );\n    urgent-foreground:           rgba ( 249, 38, 114, 100 % );\n    alternate-urgent-background: rgba ( 39, 40, 34, 0 % );\n    active-foreground:           rgba ( 166, 226, 42, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 166, 226, 42, 100 % );\n    alternate-active-background: rgba ( 39, 40, 34, 0 % );\n    background:                  rgba ( 39, 40, 34, 93 % );\n    bordercolor:                 rgba ( 0, 43, 54, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 39, 40, 34, 0 % );\n    selected-normal-background:  rgba ( 20, 20, 17, 100 % );\n    separatorcolor:              rgba ( 230, 219, 116, 100 % );\n    urgent-background:           rgba ( 39, 40, 34, 0 % );\n    selected-urgent-background:  rgba ( 249, 38, 114, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            transparent;\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 39, 40, 34, 0 % );\n    selected-active-background:  rgba ( 20, 20, 17, 100 % );\n}\nwindow {\n    border-color:     black/30%;\n    background-color: darkgrey/ 95%;\n    border:           2px;\n    padding:          0px;\n    border-radius:    10px;\n    padding:          0.5em;\n    spacing:          0px;\n\n    anchor:         north;\n    location:       center;\n    y-offset:       -15.5em;\n\n\n    children: [ inputbar, message, wrapper-mode-switcher, listview , pagerbox ];\n}\n\n\npagerbox {\n    expand: false;\n    orientation: horizontal;\n    children: [ icon-left, pad, icon-right ];\n}\n\npad {\n  expand: true;\n}\nicon-left {\n    expand: false;\n    filename: \"go-previous\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-page-prev\";\n}\n\nicon-right {\n    expand: false;\n    filename: \"go-next\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-page-next\";\n}\n\n\n\nwrapper-mode-switcher {\n    orientation: horizontal;\n\n    expand:     false;\n    spacing:    0;\n    children: [ icon-ms-ic1, mode-switcher, icon-ms-ic2 ];\n}\nicon-ms-ic1 {\n    filename: \"go-previous\";\n}\nicon-ms-ic2 {\n    filename: \"go-next\";\n}\nicon-ms-ic1,icon-ms-ic2 {\n    size: 16;\n    vertical-align: 0.8;\n    expand:        false;\n    border:       0px 0px 2px ;\n    border-color: @separatorcolor;\n}\n\nmode-switcher {\n    border:  0px;\n    spacing: 0px;\n    expand: true;\n}\n\nbutton {\n    padding:      2px;\n    border:       0px 0px 2px ;\n    border-color: @separatorcolor;\n}\nbutton selected.normal {\n    text-color: white;\n    background-color: black/50%;\n\n    border:       2px 2px 0px ;\n    border-color: @separatorcolor;\n    border-radius:    10px 10px 0 0;\n}\n\n\nsidebar {\n    expand: false;\n}\n\nmessage {\n    text-color:       black;\n    background-color: lightgrey / 50%;\n    border-color:     grey;\n    border:           2px;\n    border-radius:    5px;\n    padding:          4px;\n    margin:           0px 0px 0.5em;\n    expand:           false;\n}\n\nlistview {\n    spacing:      2px ;\n    scrollbar:    false;\n    padding:      0.5em;\n    background-color: black/50%;\n\n    expand:       true;\n    border:       0px 2px 2px ;\n    border-color: @separatorcolor;\n    border-radius: 0px 0px 10px 10px;\n}\nelement {\n    border:  1;\n    border-color: transparent;\n    padding: 4px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    border:  1;\n    border-color: grey/80%;\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    border:  1;\n    border-color: grey/80%;\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    border:  1;\n    border-color: grey/80%;\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nsidebar {\n    border:       2px 0px 0px ;\n    border-color: @separatorcolor;\n}\ninputbar {\n    text-color: @normal-foreground;\n    padding: 0px 0px 0.5em;\n}\ncase-indicator {\n    text-color: @normal-foreground;\n}\n\nwrapper {\n    orientation: horizontal;\n    text-color:       black;\n    background-color: white / 70%;\n    border-color:     grey;\n\n    border: 2px;\n    border-radius: 5px;\n    padding: 4px;\n    children:   [ icon-k, entry, icon-paste];\n    spacing:  0.5em;\n}\nbutton-paste {\n    expand: false;\n    str: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-cancel\";\n}\nicon-paste {\n    expand: false;\n    filename: \"gtk-paste\";\n    size: 24;\n    vertical-align: 0.5;\n    action: \"kb-primary-paste\";\n}\nicon-k {\n    expand: false;\n    filename: \"input-keyboard\";\n    size: 24;\n    vertical-align: 0.5;\n\n}\nentry {\n    vertical-align: 0.5;\n}\ninputbar {\n    children:   [ wrapper ];\n}\n\nerror-message {\n    background-color: darkred/10%;\n    border-color: darkred;\n    border-radius: 10px;\n    border: 2px;\n    padding: 0.5em;\n\n}\n\n"
  },
  {
    "path": "themes/fancy2.rasi",
    "content": "/**\n * Edited by: Dave Davenport\n * User: Rasi\n * Copyright: Rasmus Steinke\n */\n\n/* global settings and color variables */\n* {\n    blue:        #A7c6E2;\n    blue-trans:  #A7c6e2aa;\n    darkblue:    #005F87;\n    green:       #00330088;\n    black:       #000000;\n    grey:        #444444;\n    orange:      #FFD391;\n    dark-orange: #FFA664;\n    light-grey:  #F5F5F5;\n    medium-grey: #D0D0D0;\n    dark-grey:   #002B36;\n    urgent:      #D75F00;\n    active:      #005F87;\n    transparent: #000000aa;\n    spacing: 0em;\n    padding: 0px;\n    background-color: white;\n    line-style: \"none\";\n}\n\nprompt-box {\n  background-color    : transparent;\n}\n\nprompt {\n  background-color    : transparent;\n  text-color          : white;\n}\n\nwindow {\n    border            : 2px;\n    border-radius     : 12px;\n    border-color      : black;\n    background-color  : transparent;\n    color             : @grey;\n}\nmainbox {\n    background-color  : @blue-trans;\n    color             : @grey;\n    spacing           : 0%;\n}\n\nlistview {\n    // Looks.\n    border-radius     : 10px;\n    border            : 5px;\n    padding           : 20px;\n    margin            : 20px 30px 30px 30px;\n    background-color  : @orange;\n    // Enable scrollbar\n    scrollbar         : false;\n    scrollbar-width   : 5px;\n    fixed-height      : true;\n    reverse           : false;\n    color             : #000000;\n    spacing           : 0.3em;\n}\nscrollbar {\n    color: @black;\n    background-color: @blue;\n    padding: 1px;\n}\nelement {\n    border: 0px;\n    padding: 0px;\n    margin: 0px;\n    spacing: 0.5em;\n    color: @black;\n    background-color: @blue;\n    children: [ element-icon, element-text ];\n}\n\nelement normal.normal {\n    color: @black;\n    background-color: @orange;\n}\nelement normal.urgent {\n    color: @urgent;\n    background-color: @light-grey;\n}\nelement normal.active {\n    color: @active;\n    background-color: @light-grey;\n}\nelement selected.normal {\n    border-radius: 0px;\n    color: @black;\n    background-color: @dark-orange;\n}\nelement selected.urgent {\n    color: @light-grey;\n    background-color: @urgent;\n}\nelement selected.active {\n    color: @light-grey;\n    background-color: @active;\n}\nelement alternate.normal {\n    color: @black;\n    background-color: @orange;\n}\nelement alternate.urgent {\n    color: @urgent;\n    background-color: @medium-grey;\n}\nelement alternate.active {\n    color: @active;\n    background-color: @medium-grey;\n}\ninputbar {\n    spacing           : 5px;\n    background-color  : #88003300;\n    border            : 0px 0px 2px 0px;\n    border-radius     : 0px;\n    padding           : 5px 10px 5px 35px;\n    background-color  : #00330088;\n    color             : @black;\n    end               : false;\n}\n\nseparator {\n    background-color  : @blue;\n    color             : #00000000;\n}\nprompt normal.normal {\n    background-color  : #00000000;\n    color             : #ffffff;\n    padding           : 0px;\n}\nentry normal.normal {\n    background-color  : #00000000;\n    color             : #ffffff;\n    padding           : 0px;\n}\ncase-indicator normal.normal {\n    background-color  : #00000000;\n    color             : #ffffff;\n    padding           : 0px;\n}\n\nmessage {\n    margin          : 30px;\n    padding         : 20px 30px 20px 20px;\n    padding         : 20px ;\n    border-radius   : 10px;\n    border          : 5px;\n}\n\nprompt-colon {\n    spacing         :    0;\n    enabled         : false;\n}\n\nelement-text, element-icon {\n  background-color  : inherit;\n  text-color        : inherit;\n  foreground-color  : inherit;\n}\n"
  },
  {
    "path": "themes/fullscreen-preview.rasi",
    "content": "/**\n * ROFI Color Theme\n *\n * Fullscreen theme with switchable PREVIEW option.\n * \n * User: Dave Davenport\n * Copyright: Dave Davenport\n */\n\n* {\n\tbackground-color: transparent;\n\ttext-color:       white;\n}\n\nwindow {\n\tfullscreen:       true;\n\tbackground-color: black/80%;\n\tpadding:          4em;\n\tchildren:         [ wrap, listview-split];\n\tspacing:          1em;\n}\n\n\n/** We add an extra child to this if PREVIEW=true */\nlistview-split {\n  orientation: horizontal;\n  spacing: 0.4em;\n  children: [listview];\n}\n\nwrap {\n\texpand: false;\n\torientation: vertical;\n\tchildren: [ inputbar, message ];\n\tbackground-image: linear-gradient(white/5%, white/40%);\n\tborder-color: lightblue;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n}\n\nicon-ib {\n\texpand: false;\n\tfilename: \"system-search\";\n\tvertical-align: 0.5;\n\thorizontal-align: 0.5;\n\tsize: 1em;\n}\ninputbar {\n\tspacing: 0.4em;\n\tpadding: 0.4em;\n\tchildren: [ icon-ib, entry ];\n}\nentry {\n\tplaceholder: \"Search\";\n\tplaceholder-color: grey;\n}\nmessage {\n\tbackground-color: red/20%;\n\tborder-color: lightsalmon;\n\tborder: 3px 0px 0px 0px;\n\tpadding: 0.4em;\n\tspacing: 0.4em;\n}\n\nlistview {\n\tflow: horizontal;\n\tfixed-columns: true;\n\tcolumns: 7;\n\tlines: 5;\n\tspacing: 1.0em;\n}\n\nelement {\n\torientation: vertical;\n\tpadding: 0.1em;\n\n\tbackground-image: linear-gradient(white/5%, white/20%);\n\tborder-color: lightblue /15%;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n\n  children: [element-icon, element-text ];\n}\nelement-icon {\n\tsize: calc(((100% - 8em) / 7 ));\n\thorizontal-align: 0.5;\n\tvertical-align: 0.5;\n}\nelement-text {\n\thorizontal-align: 0.5;\n\tvertical-align: 0.5;\n  padding: 0.2em;\n}\n\nelement selected {\n\tbackground-image: linear-gradient(white/25%, white/10%);\n\tborder-color: lightblue;\n\tborder: 3px;\n\tborder-radius: 0.4em;\n}\n\n/**\n * Launching rofi with environment PREVIEW set to true\n * will split the screen and show a preview widget.\n */\n@media ( enabled: env(PREVIEW, false)) {\n  /** preview widget */\n  icon-current-entry {\n    expand:          true;\n    size:            80%;\n  }\n  listview-split {\n    children: [listview, icon-current-entry];\n  }\n  listview {\n  columns: 4;\n  }\n\n}\n\n@media ( enabled: env(NO_IMAGE, false)) {\n\tlistview {\n\t\tcolumns: 1;\n\t\tspacing: 0.4em;\n\t}\n\telement {\n\t\tchildren: [ element-text ];\n\t}\n\telement-text {\n\t\thorizontal-align: 0.0;\n\t}\n}\n"
  },
  {
    "path": "themes/glue_pro_blue.rasi",
    "content": "/******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n ******************************************************************************/\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 255, 255, 255, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: transparent;\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 255, 195, 156, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 243, 132, 61, 100 % );\n    alternate-urgent-background: transparent;\n    active-foreground:           rgba ( 38, 139, 210, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 32, 81, 113, 100 % );\n    alternate-active-background: transparent;\n    background:                  transparent;\n    bordercolor:                 rgba ( 57, 57, 57, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           transparent;\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 38, 139, 210, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 38, 139, 210, 100 % );\n    urgent-background:           transparent;\n    selected-urgent-background:  rgba ( 38, 139, 210, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 57, 57, 57, 100 % );\n    selected-active-background:  rgba ( 38, 139, 210, 100 % );\n}\nwindow {\n    background-color: rgba ( 57, 57, 57, 95 % );\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nbutton {\n    background-color: @background;\n    text-color:       @foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/gruvbox-common.rasinc",
    "content": "/* ==========================================================================\n   File: gruvbox-common.rasi\n   Desc: Shared rules between all gruvbox themes\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:06:47 PST -0800\n   ========================================================================== */\n\nwindow {\n    background-color: @background;\n    border:           2;\n    padding:          2;\n}\n\nmainbox {\n    border:  0;\n    padding: 0;\n}\n\nmessage {\n    border:       2px 0 0;\n    border-color: @separatorcolor;\n    padding:      1px;\n}\n\ntextbox {\n    highlight:  @highlight;\n    text-color: @foreground;\n}\n\nlistview {\n    border:       2px solid 0 0;\n    padding:      2px 0 0;\n    border-color: @separatorcolor;\n    spacing:      2px;\n    scrollbar:    @scrollbar;\n}\n\nelement {\n    border:  0;\n    padding: 2px;\n}\n\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\n\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\n\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\n\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\n\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\n\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\n\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\n\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\n\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\n\nscrollbar {\n    width:        4px;\n    border:       0;\n    handle-color: @scrollbar-handle;\n    handle-width: 8px;\n    padding:      0;\n}\n\nmode-switcher {\n    border:       2px 0 0;\n    border-color: @separatorcolor;\n}\n\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    2px;\n    children:   [ prompt, textbox-prompt-sep, entry, case-indicator ];\n}\n\ncase-indicator,\nentry,\nprompt,\nbutton {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\n\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\n\ntextbox-prompt-sep {\n    expand:     false;\n    str:        \":\";\n    text-color: @normal-foreground;\n    margin:     0 0.3em 0 0;\n}\nelement-text, element-icon {\n    background-color: inherit;\n    text-color:       inherit;\n}\n"
  },
  {
    "path": "themes/gruvbox-dark-hard.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-dark-hard.rasi\n   Desc: Gruvbox dark (hard contrast) color theme for Rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:04:26 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox dark colors */\n    gruvbox-dark-bg0-hard:     #1d2021;\n    gruvbox-dark-bg0:          #282828;\n    gruvbox-dark-bg2:          #504945;\n    gruvbox-dark-fg0:          #fbf1c7;\n    gruvbox-dark-fg1:          #ebdbb2;\n    gruvbox-dark-red-dark:     #cc241d;\n    gruvbox-dark-red-light:    #fb4934;\n    gruvbox-dark-yellow-dark:  #d79921;\n    gruvbox-dark-yellow-light: #fabd2f;\n    gruvbox-dark-gray:         #a89984;\n\n    /* Theme colors */\n    background:                  @gruvbox-dark-bg0-hard;\n    background-color:            @background;\n    foreground:                  @gruvbox-dark-fg1;\n    border-color:                @gruvbox-dark-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-dark-bg0;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-dark-bg2;\n    selected-normal-foreground:  @gruvbox-dark-fg0;\n\n    active-background:           @gruvbox-dark-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-dark-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-dark-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-dark-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/gruvbox-dark-soft.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-dark-soft.rasi\n   Desc: Gruvbox dark (soft contrast) color theme for Rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:04:37 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox dark colors */\n    gruvbox-dark-bg0-soft:     #32302f;\n    gruvbox-dark-bg1:          #3c3836;\n    gruvbox-dark-bg3:          #665c54;\n    gruvbox-dark-fg0:          #fbf1c7;\n    gruvbox-dark-fg1:          #ebdbb2;\n    gruvbox-dark-red-dark:     #cc241d;\n    gruvbox-dark-red-light:    #fb4934;\n    gruvbox-dark-yellow-dark:  #d79921;\n    gruvbox-dark-yellow-light: #fabd2f;\n    gruvbox-dark-gray:         #a89984;\n\n    /* Theme colors */\n    background:                  @gruvbox-dark-bg0-soft;\n    background-color:            @background;\n    foreground:                  @gruvbox-dark-fg1;\n    border-color:                @gruvbox-dark-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-dark-bg1;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-dark-bg3;\n    selected-normal-foreground:  @gruvbox-dark-fg0;\n\n    active-background:           @gruvbox-dark-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-dark-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-dark-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-dark-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/gruvbox-dark.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-dark.rasi\n   Desc: Gruvbox dark color theme for Rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 04:08:43 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox dark colors */\n    gruvbox-dark-bg0:          #282828;\n    gruvbox-dark-bg0-soft:     #32302f;\n    gruvbox-dark-bg3:          #665c54;\n    gruvbox-dark-fg0:          #fbf1c7;\n    gruvbox-dark-fg1:          #ebdbb2;\n    gruvbox-dark-red-dark:     #cc241d;\n    gruvbox-dark-red-light:    #fb4934;\n    gruvbox-dark-yellow-dark:  #d79921;\n    gruvbox-dark-yellow-light: #fabd2f;\n    gruvbox-dark-gray:         #a89984;\n\n    /* Theme colors */\n    background:                  @gruvbox-dark-bg0;\n    background-color:            @background;\n    foreground:                  @gruvbox-dark-fg1;\n    border-color:                @gruvbox-dark-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-dark-bg0-soft;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-dark-bg3;\n    selected-normal-foreground:  @gruvbox-dark-fg0;\n\n    active-background:           @gruvbox-dark-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-dark-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-dark-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-dark-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/gruvbox-light-hard.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-light-hard.rasi\n   Desc: Gruvbox light (hard contrast) color theme for Rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:04:48 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox light colors */\n    gruvbox-light-bg0-hard:     #f9f5d7;\n    gruvbox-light-bg0:          #fbf1c7;\n    gruvbox-light-bg1:          #ebdbb2;\n    gruvbox-light-fg0:          #282828;\n    gruvbox-light-fg1:          #3c3836;\n    gruvbox-light-red-dark:     #9d0006;\n    gruvbox-light-red-light:    #cc241d;\n    gruvbox-light-yellow-dark:  #b57614;\n    gruvbox-light-yellow-light: #d79921;\n    gruvbox-light-gray:         #7c6f64;\n\n    /* Theme colors */\n    background:                  @gruvbox-light-bg0-hard;\n    background-color:            @background;\n    foreground:                  @gruvbox-light-fg1;\n    border-color:                @gruvbox-light-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-light-bg0;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-light-bg1;\n    selected-normal-foreground:  @gruvbox-light-fg0;\n\n    active-background:           @gruvbox-light-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-light-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-light-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-light-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/gruvbox-light-soft.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-light-soft.rasi\n   Desc: Gruvbox light (soft contrast) color theme for Rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:05:38 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox light colors */\n    gruvbox-light-bg0-soft:     #f2e5bc;\n    gruvbox-light-bg1:          #ebdbb2;\n    gruvbox-light-bg2:          #d5c4a1;\n    gruvbox-light-fg0:          #282828;\n    gruvbox-light-fg1:          #3c3836;\n    gruvbox-light-red-dark:     #9d0006;\n    gruvbox-light-red-light:    #cc241d;\n    gruvbox-light-yellow-dark:  #b57614;\n    gruvbox-light-yellow-light: #d79921;\n    gruvbox-light-gray:         #7c6f64;\n\n    /* Theme colors */\n    background:                  @gruvbox-light-bg0-soft;\n    background-color:            @background;\n    foreground:                  @gruvbox-light-fg1;\n    border-color:                @gruvbox-light-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-light-bg1;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-light-bg2;\n    selected-normal-foreground:  @gruvbox-light-fg0;\n\n    active-background:           @gruvbox-light-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-light-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-light-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-light-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/gruvbox-light.rasi",
    "content": "/* ==========================================================================\n   Rofi color theme\n\n   Based on the Gruvbox color scheme for Vim by morhetz\n   https://github.com/morhetz/gruvbox\n\n   File: gruvbox-light.rasi\n   Desc: Gruvbox light color theme for rofi\n   Author: bardisty <b@bah.im>\n   Source: https://github.com/bardisty/gruvbox-rofi\n   Modified: Mon Feb 12 2018 06:06:06 PST -0800\n   ========================================================================== */\n\n* {\n    /* Theme settings */\n    highlight: bold italic;\n    scrollbar: true;\n\n    /* Gruvbox light colors */\n    gruvbox-light-bg0:          #fbf1c7;\n    gruvbox-light-bg0-soft:     #f2e5bc;\n    gruvbox-light-bg2:          #d5c4a1;\n    gruvbox-light-fg0:          #282828;\n    gruvbox-light-fg1:          #3c3836;\n    gruvbox-light-gray:         #7c6f64;\n    gruvbox-light-red-dark:     #9d0006;\n    gruvbox-light-red-light:    #cc241d;\n    gruvbox-light-yellow-dark:  #b57614;\n    gruvbox-light-yellow-light: #d79921;\n\n    /* Theme colors */\n    background:                  @gruvbox-light-bg0;\n    background-color:            @background;\n    foreground:                  @gruvbox-light-fg1;\n    border-color:                @gruvbox-light-gray;\n    separatorcolor:              @border-color;\n    scrollbar-handle:            @border-color;\n\n    normal-background:           @background;\n    normal-foreground:           @foreground;\n    alternate-normal-background: @gruvbox-light-bg0-soft;\n    alternate-normal-foreground: @foreground;\n    selected-normal-background:  @gruvbox-light-bg2;\n    selected-normal-foreground:  @gruvbox-light-fg0;\n\n    active-background:           @gruvbox-light-yellow-dark;\n    active-foreground:           @background;\n    alternate-active-background: @active-background;\n    alternate-active-foreground: @active-foreground;\n    selected-active-background:  @gruvbox-light-yellow-light;\n    selected-active-foreground:  @active-foreground;\n\n    urgent-background:           @gruvbox-light-red-dark;\n    urgent-foreground:           @background;\n    alternate-urgent-background: @urgent-background;\n    alternate-urgent-foreground: @urgent-foreground;\n    selected-urgent-background:  @gruvbox-light-red-light;\n    selected-urgent-foreground:  @urgent-foreground;\n}\n\n@import \"gruvbox-common\"\n\n"
  },
  {
    "path": "themes/iggy.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n\n* {\n  /* Default background color */\n  background-color: transparent;\n  text-color:       white;\n}\n\n\nwindow {\n  padding: 1em;\n\n  border-color: lightgreen;\n  border:       5px;\n  border-radius: 10px;\n\n  width:  1024px; \n//  height: 768px;\n\n  background-color: darkgreen;\n\n  background-image: url(\"iggy.jpg\", width);\n}\n\nmainbox {\n  spacing: 0px;\n  children: [inputbar,wrapper-mode-switcher,listview];\n}\n\nelement {\n  background: transparent;\n  children: [ element-icon, element-text ];\n}\nelement,element-text,element-icon, button {\n    cursor: pointer;\n}\n\ninputbar {\n  margin: 0px 0px 0.5em 0em;\n  spacing: 0.4em;\n  children: [ button-iggy1, entry,overlay,case-indicator, button-iggy2];\n}\n\nbutton-iggy1, button-iggy2 {\n  expand: false;\n  content: \"🐢\";\n  action: \"kb-primary-paste\";\n  horizontal-align: 0.5;\n}\nbutton-iggy2 {\n  action: \"kb-screenshot\";\n}\n\nlistview, inputbar, message {\n  padding: 0.5em;  \n  border-color: lightgreen;\n  border:        5px;\n  border-radius: 10px;\n  background-color: black/70%;\n\n  columns: 4;\n  lines:   4;\n}\nlistview {\n  border:       0px 5px 5px 5px;\n  border-radius: 0px 0px 10px 10px;\n}\n\n\nelement {\n    border:  0;\n    padding:      10px;\n    font:         \"Mono 8\";\n    orientation: vertical;\n}\nelement-icon {\n  size: 6em;\n}\n\nelement  selected {\n  border-color: lightgreen;\n  border:       5px;\n  border-radius: 10px;\n  background-color: lightgreen/20%;\n}\n\nelement-text, element-icon {\n  font:             inherit; \n  horizontal-align: 0.5;\n}\n\nwrapper-mode-switcher {\n    orientation: horizontal;\n\n    expand:     false;\n    spacing:    0;\n    children: [ icon-ms-ic1, mode-switcher, icon-ms-ic2 ];\n}\nicon-ms-ic1 {\n    filename: \"go-previous\";\n    action: \"kb-mode-previous\";\n}\nicon-ms-ic2 {\n    filename: \"go-next\";\n    action: \"kb-mode-next\";\n}\nicon-ms-ic1,icon-ms-ic2 {\n    size: 16;\n    vertical-align: 0.8;\n    expand:        false;\n    border:       0px 0px 5px ;\n    border-color: lightgreen;\n}\n\nmode-switcher {\n    border:  0px;\n    spacing: 0px;\n    expand: true;\n}\nbutton {\n    text-color: white;\n    border:       0px 0px 5px ;\n    border-color: lightgreen;\n    border-radius:    10px 10px 0 0;\n    background-image: linear-gradient(to bottom, darkgreen/50%, black/70%);\n    horizontal-align: 0.5;\n}\nbutton selected.normal {\n    text-color: white;\n    margin: 0px;\n    padding: 0px;\n\n    border:       5px 5px 0px ;\n    border-color: lightgreen;\n    border-radius:    10px 10px 0 0;\n    background-image: linear-gradient(to bottom, darkgreen, black/70%);\n}\n\nentry {\n    placeholder: \"Iggy\";\n    placeholder-color: darkgrey/30%;\n  }\n"
  },
  {
    "path": "themes/lb.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    selected-normal-foreground:  rgba ( 51, 51, 51, 100 % );\n    foreground:                  rgba ( 17, 170, 170, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 255, 255, 255, 7 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 51, 51, 51, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 255, 153, 153, 100 % );\n    alternate-urgent-background: rgba ( 255, 255, 255, 7 % );\n    active-foreground:           rgba ( 170, 170, 17, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 51, 51, 51, 100 % );\n    alternate-active-background: rgba ( 255, 255, 255, 7 % );\n    background:                  rgba ( 51, 51, 51, 93 % );\n    bordercolor:                 rgba ( 17, 170, 170, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 0, 0, 0 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 17, 170, 170, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 17, 170, 170, 100 % );\n    urgent-background:           rgba ( 0, 0, 0, 0 % );\n    selected-urgent-background:  rgba ( 255, 153, 153, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 0, 0, 0 % );\n    selected-active-background:  rgba ( 170, 170, 17, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/material.rasi",
    "content": "/*\n * ROFI color theme\n *\n * Based on Base16 Material Color Scheme (https://github.com/ntpeters/base16-materialtheme-scheme)\n *\n * Modified by: Dave Davenport\n * User: Tomaszal\n * Copyright: Tomas Zaluckij\n */\n\n* {\n\tbase00: #263238;\n\tbase01: #2E3C43;\n\tbase02: #314549;\n\tbase03: #546E7A;\n\tbase04: #B2CCD6;\n\tbase05: #EEFFFF;\n\tbase06: #EEFFFF;\n\tbase07: #FFFFFF;\n\tbase08: #F07178;\n\tbase09: #F78C6C;\n\tbase0A: #FFCB6B;\n\tbase0B: #C3E88D;\n\tbase0C: #89DDFF;\n\tbase0D: #82AAFF;\n\tbase0E: #C792EA;\n\tbase0F: #FF5370;\n\n\t/*base0D: #00BCD4;*/\n\n\tspacing: 0;\n\tbackground-color: transparent;\n\n}\n\nwindow {\n\ttransparency: \"real\";\n\tbackground-color: #263238CC; /*base00 + CC (80% opacity)*/\n}\n\nmainbox {\n\tchildren: [inputbar, message, mode-switcher, listview];\n\tspacing: 30px;\n\tpadding: 30px 0;\n\tborder: 1px;\n\tborder-color: @base0D;\n}\n\ninputbar {\n\tpadding: 0 30px;\n\tchildren: [prompt, textbox-prompt-colon, entry, case-indicator];\n}\n\nprompt {\n\ttext-color: @base0D;\n}\n\ntextbox-prompt-colon {\n\texpand: false;\n\tstr: \":\";\n\tmargin: 0 1ch 0 0;\n\ttext-color: @base0D;\n}\n\nentry {\n\ttext-color: @base07;\n}\n\ncase-indicator {\n\ttext-color: @base0F;\n}\n\nmode-switcher, message {\n\tborder: 1px 0;\n\tborder-color: @base0D;\n}\n\nbutton, textbox {\n\tbackground-color: @base03;\n\ttext-color: @base07;\n\tpadding: 5px;\n}\n\nbutton selected {\n\tbackground-color: @base0D;\n}\n\nlistview {\n\tscrollbar: true;\n\tmargin: 0 10px 0 30px;\n}\n\nscrollbar {\n\tbackground-color: @base03;\n\thandle-color: @base0D;\n\thandle-width: 10px;\n\tborder: 0 1px;\n\tborder-color: @base0D;\n\tmargin: 0 0 0 20px;\n}\n\nelement {\n\tpadding: 5px;\n  spacing: 5px;\n\thighlight: bold underline;\n\tchildren: [element-icon, element-text];\n}\nelement-text, element-icon {\n\tbackground-color : inherit;\n\ttext-color\t     : inherit;\n\tforeground-color : inherit;\n}\n\nelement normal {\n\tbackground-color: transparent;\n}\n\nelement selected {\n\tbackground-color: @base0D;\n}\n\nelement alternate {\n\t/*background-color: @base03;*/\n}\n\nelement normal normal, element selected normal, element alternate normal {\n\ttext-color: @base07;\n}\n\nelement normal urgent, element selected urgent, element alternate urgent {\n\ttext-color: @base0F;\n}\n\nelement normal active, element selected active, element alternate active {\n\ttext-color: @base0B;\n}\n"
  },
  {
    "path": "themes/paper-float.rasi",
    "content": "/**\n * A floating box version of the paper theme.\n *\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    blue:  #0000FF;\n    white: #FFFFFF;\n    black: #000000;\n    grey:  #eeeeee;\n\n    spacing: 2;\n    background-color: #00000000;\n    border-color: #444444FF;\n    anchor: north;\n    location: center;\n}\nwindow {\n    transparency: \"real\";\n    background-color: #00000000;\n    border: 0;\n    padding: 0% 0% 1em 0%;\n    x-offset: 0;\n    y-offset: -10%;\n}\nmainbox {\n    padding: 0px;\n    border: 0;\n    spacing: 1%;\n}\nmessage {\n    border: 2px;\n    padding: 1em;\n    background-color: @white;\n    text-color: @black;\n}\ntextbox normal {\n    text-color: #002B36FF;\n    padding: 0;\n    border: 0;\n}\nlistview {\n    fixed-height: 1;\n    border: 2px;\n    padding: 1em;\n    reverse: false;\n\n    columns: 1;\n    background-color: @white;\n}\nelement {\n    border: 0;\n    padding: 2px;\n    highlight: bold ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement normal.normal {\n    text-color: #002B36FF;\n    background-color: #F5F5F500;\n}\nelement normal.urgent {\n    text-color: #D75F00FF;\n    background-color: #F5F5F5FF;\n}\nelement normal.active {\n    text-color: #005F87FF;\n    background-color: #F5F5F5FF;\n}\nelement selected.normal {\n    text-color: #F5F5F5FF;\n    background-color: #4271AEFF;\n}\nelement selected.urgent {\n    text-color: #F5F5F5FF;\n    background-color: #D75F00FF;\n}\nelement selected.active {\n    text-color: #F5F5F5FF;\n    background-color: #005F87FF;\n}\nelement alternate.normal {\n    text-color: #002B36FF;\n    background-color: #D0D0D0FF;\n}\nelement alternate.urgent {\n    text-color: #D75F00FF;\n    background-color: #D0D0D0FF;\n}\nelement alternate.active {\n    text-color: #005F87FF;\n    background-color: #D0D0D0FF;\n}\nscrollbar {\n    border: 0;\n    padding: 0;\n}\ninputbar {\n    spacing: 0;\n    border: 2px;\n    padding: 0.5em 1em;\n    background-color: @grey;\n    index: 0;\n}\ninputbar normal {\n    foreground-color: #002B36FF;\n    background-color: #F5F5F500;\n}\nmode-switcher {\n    border: 2px;\n    padding: 0.5em 1em;\n    background-color: @grey;\n    index: 10;\n}\nbutton selected {\n    text-color: #4271AEFF;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: var(black);\n}\nerror-message {\n    border: 2px;\n    padding: 1em;\n    background-color: #FF8888;\n    text-color: @black;\n}\n"
  },
  {
    "path": "themes/purple.rasi",
    "content": "/******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n ******************************************************************************/\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 180, 180, 180, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 47, 30, 46, 63 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 239, 97, 85, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 239, 97, 85, 100 % );\n    alternate-urgent-background: rgba ( 47, 30, 46, 18 % );\n    active-foreground:           rgba ( 129, 91, 164, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 129, 91, 164, 100 % );\n    alternate-active-background: rgba ( 47, 30, 46, 18 % );\n    background:                  rgba ( 47, 30, 46, 100 % );\n    bordercolor:                 rgba ( 239, 97, 85, 21 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 47, 30, 46, 63 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 129, 91, 164, 33 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 239, 97, 85, 18 % );\n    urgent-background:           rgba ( 47, 30, 46, 15 % );\n    selected-urgent-background:  rgba ( 129, 91, 164, 33 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 47, 30, 46, 15 % );\n    selected-active-background:  rgba ( 129, 91, 164, 33 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/sidebar-v2.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    background-color:  transparent; \n    // Bold, Italic, Underline\n    highlight:     bold #ffffff;\n}\nwindow {\n    background-color: black / 80%;\n    border-color:     white;\n    border-radius:    0 15mm 15mm 0;\n\n    padding: 10mm;\n\n    height:   100%;\n    width:    150mm;\n    border:  1mm 1mm 1mm 0px;\n    text-color: white;\n\n\n    location: west;\n    anchor:   west;\n}\ninputbar {\n    background-color: transparent;\n    text-color:       black;\n    children: [prompt, entry, textbox-end];\n    spacing: 1mm;\n}\nprompt {\n  border-radius: 5mm 0mm 0mm 5mm;\n  width: 15mm;\n}\ntextbox-end {\n  border-radius: 0mm 5mm 5mm 0mm;\n  width: 15mm;\n  expand: false;\n}\nentry {\n  background-color: grey;\n}\nprompt, entry, textbox-end, num-filtered-rows {\n  background-color: white;\n  text-color: inherit;\n  padding: 2mm;\n  vertical-align: 0.5;\n}\nelement {\n    border-radius: 5mm;\n    children: [element-icon];\n}\ntextbox-current-entry {\n    border-radius: 5mm;\n    background-color: lightgreen;\n    text-color: black;\n    placeholder: \"n/a\";\n    padding: 2mm;\n    horizontal-align: 0.5;\n  }\nelement-icon {\n  expand: true;\n  size: 10mm;\n  vertial-align: 0.5;\n  horizontal-align: 0.5;\n  padding: 2mm;\n}\n\n\nmainbox {\n    expand: true;\n    background-color: transparent;\n    spacing:  5mm;\n    children: [\n                inputbar,\n                listview,\n                icon-current-entry,\n                textbox-current-entry\n    ];\n}\nicon-current-entry {\n    size: 100mm;\n  }\nlistview {\n    padding: 0em;\n    dynamic: false;\n    lines: 0;\n    columns: 8;\n    flow: horizontal;\n}\nelement selected  normal {\n    background-color: MediumSlateBlue;\n}\nelement normal active {\n    text-color: MediumTurquoise;\n}\nelement normal urgent {\n    text-color: red;\n}\nelement alternate normal {\n}\nelement alternate active {\n    text-color: MediumTurquoise;\n}\nelement alternate urgent {\n    text-color: MediumVioletRed;\n}\nelement selected active {\n    background-color: MediumTurquoise;\n    text-color: black;\n}\nelement selected urgent {\n    background-color: MediumVioletRed;\n    text-color: black;\n}\nerror-message {\n    expand: true;\n    background-color: red;\n    border-color: darkred;\n    border: 2px;\n    padding: 1em;\n}\n"
  },
  {
    "path": "themes/sidebar.rasi",
    "content": "/**\n * ROFI Color theme\n * User: Qball\n * Copyright: Dave Davenport\n */\n\n* {\n    text-color:  #ffeedd;\n    background-color:  rgba(0,0,0,0);\n    dark: #1c1c1c;\n    // Black\n    black:       #3d352a;\n    lightblack:  #554444;\n    //\n    // Red\n    red:         #cd5c5c;\n    lightred:    #cc5533;\n    //\n    // Green\n    green:       #86af80;\n    lightgreen:  #88cc22;\n    //\n    // Yellow\n    yellow:      #e8ae5b;\n    lightyellow:     #ffa75d;\n    //\n    // Blue\n    blue:      #6495ed;\n    lightblue:     #87ceeb;\n    //\n    // Magenta\n    magenta:      #deb887;\n    lightmagenta:     #996600;\n    //\n    // Cyan\n    cyan:      #b0c4de;\n    lightcyan:     #b0c4de;\n    //\n    // White\n    white:      #bbaa99;\n    lightwhite:     #ddccbb;\n    //\n    // Bold, Italic, Underline\n    highlight:     bold #ffffff;\n}\nwindow {\n    height:   100%;\n    width: 30em;\n    location: west;\n    anchor:   west;\n    border:  0px 2px 0px 0px;\n    text-color: @lightwhite;\n}\nmode-switcher {\n    border: 2px 0px 0px 0px;\n    background-color: @lightblack;\n    padding: 4px;\n}\nbutton selected {\n    border-color: @lightgreen;\n    text-color: @lightgreen;\n}\ninputbar {\n    background-color: @lightblack;\n    text-color: @lightgreen;\n    padding: 4px;\n    border: 0px 0px 2px 0px;\n}\nmainbox {\n    expand: true;\n    background-color: #1c1c1cee;\n    spacing: 1em;\n}\nlistview {\n    padding: 0em 0.4em 0em 1em;\n    dynamic: false;\n    lines: 0;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement selected  normal {\n    background-color: @blue;\n}\nelement normal active {\n    text-color: @lightblue;\n}\nelement normal urgent {\n    text-color: @lightred;\n}\nelement alternate normal {\n}\nelement alternate active {\n    text-color: @lightblue;\n}\nelement alternate urgent {\n    text-color: @lightred;\n}\nelement selected active {\n    background-color: @lightblue;\n    text-color: @dark;\n}\nelement selected urgent {\n    background-color: @lightred;\n    text-color: @dark;\n}\nerror-message {\n    expand: true;\n    background-color: red;\n    border-color: darkred;\n    border: 2px;\n    padding: 1em;\n}\n"
  },
  {
    "path": "themes/solarized.rasi",
    "content": "/******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n ******************************************************************************/\n* {\n    selected-normal-foreground:  rgba ( 129, 147, 150, 100 % );\n    foreground:                  rgba ( 129, 147, 150, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 0, 43, 55, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 218, 66, 129, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 218, 66, 129, 100 % );\n    alternate-urgent-background: rgba ( 0, 43, 55, 100 % );\n    active-foreground:           rgba ( 0, 142, 212, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 0, 142, 212, 100 % );\n    alternate-active-background: rgba ( 0, 43, 55, 100 % );\n    background:                  rgba ( 0, 43, 55, 100 % );\n    bordercolor:                 rgba ( 0, 43, 55, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 43, 55, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 0, 54, 66, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 0, 54, 66, 100 % );\n    urgent-background:           rgba ( 0, 43, 55, 100 % );\n    selected-urgent-background:  rgba ( 0, 54, 66, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 43, 55, 100 % );\n    selected-active-background:  rgba ( 0, 54, 66, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  },
  {
    "path": "themes/solarized_alternate.rasi",
    "content": "/******************************************************************************\n * ROFI Color theme\n * User: Rasi\n * Copyright: Rasmus Steinke\n ******************************************************************************/\n* {\n    selected-normal-foreground:  rgba ( 255, 255, 255, 100 % );\n    foreground:                  rgba ( 129, 147, 150, 100 % );\n    normal-foreground:           @foreground;\n    alternate-normal-background: rgba ( 0, 54, 67, 100 % );\n    red:                         rgba ( 220, 50, 47, 100 % );\n    selected-urgent-foreground:  rgba ( 137, 6, 97, 100 % );\n    blue:                        rgba ( 38, 139, 210, 100 % );\n    urgent-foreground:           rgba ( 218, 66, 129, 100 % );\n    alternate-urgent-background: rgba ( 0, 54, 67, 100 % );\n    active-foreground:           rgba ( 0, 142, 212, 100 % );\n    lightbg:                     rgba ( 238, 232, 213, 100 % );\n    selected-active-foreground:  rgba ( 102, 198, 255, 100 % );\n    alternate-active-background: rgba ( 0, 54, 67, 100 % );\n    background:                  rgba ( 0, 43, 55, 100 % );\n    bordercolor:                 rgba ( 0, 43, 55, 100 % );\n    alternate-normal-foreground: @foreground;\n    normal-background:           rgba ( 0, 43, 55, 100 % );\n    lightfg:                     rgba ( 88, 104, 117, 100 % );\n    selected-normal-background:  rgba ( 0, 142, 212, 100 % );\n    border-color:                @foreground;\n    spacing:                     2;\n    separatorcolor:              rgba ( 0, 54, 66, 100 % );\n    urgent-background:           rgba ( 0, 43, 55, 100 % );\n    selected-urgent-background:  rgba ( 0, 142, 212, 100 % );\n    alternate-urgent-foreground: @urgent-foreground;\n    background-color:            rgba ( 0, 0, 0, 0 % );\n    alternate-active-foreground: @active-foreground;\n    active-background:           rgba ( 0, 43, 55, 100 % );\n    selected-active-background:  rgba ( 0, 142, 212, 100 % );\n}\nwindow {\n    background-color: @background;\n    border:           1;\n    padding:          5;\n}\nmainbox {\n    border:  0;\n    padding: 0;\n}\nmessage {\n    border:       1px dash 0px 0px ;\n    border-color: @separatorcolor;\n    padding:      1px ;\n}\ntextbox {\n    text-color: @foreground;\n}\nlistview {\n    fixed-height: 0;\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n    spacing:      2px ;\n    scrollbar:    true;\n    padding:      2px 0px 0px ;\n}\nelement {\n    border:  0;\n    padding: 1px ;\n}\nelement-text {\n    background-color: inherit;\n    text-color:       inherit;\n}\nelement.normal.normal {\n    background-color: @normal-background;\n    text-color:       @normal-foreground;\n}\nelement.normal.urgent {\n    background-color: @urgent-background;\n    text-color:       @urgent-foreground;\n}\nelement.normal.active {\n    background-color: @active-background;\n    text-color:       @active-foreground;\n}\nelement.selected.normal {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\nelement.selected.urgent {\n    background-color: @selected-urgent-background;\n    text-color:       @selected-urgent-foreground;\n}\nelement.selected.active {\n    background-color: @selected-active-background;\n    text-color:       @selected-active-foreground;\n}\nelement.alternate.normal {\n    background-color: @alternate-normal-background;\n    text-color:       @alternate-normal-foreground;\n}\nelement.alternate.urgent {\n    background-color: @alternate-urgent-background;\n    text-color:       @alternate-urgent-foreground;\n}\nelement.alternate.active {\n    background-color: @alternate-active-background;\n    text-color:       @alternate-active-foreground;\n}\nscrollbar {\n    width:        4px ;\n    border:       0;\n    handle-width: 8px ;\n    padding:      0;\n}\nmode-switcher {\n    border:       2px dash 0px 0px ;\n    border-color: @separatorcolor;\n}\nbutton.selected {\n    background-color: @selected-normal-background;\n    text-color:       @selected-normal-foreground;\n}\ninputbar {\n    spacing:    0;\n    text-color: @normal-foreground;\n    padding:    1px ;\n}\ncase-indicator {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nentry {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\nprompt {\n    spacing:    0;\n    text-color: @normal-foreground;\n}\ninputbar {\n    children:   [ prompt,textbox-prompt-colon,entry,case-indicator ];\n}\ntextbox-prompt-colon {\n    expand:     false;\n    str:        \":\";\n    margin:     0px 0.3em 0em 0em ;\n    text-color: @normal-foreground;\n}\n"
  }
]