File gnome-kiosk-45.0.obscpio of Package gnome-kiosk

07070100000000000081A40000000000000000000000016506F4B7000000B9000000000000000000000000000000000000001C00000000gnome-kiosk-45.0/.gitignore*.la
*.lo
*.o
.deps
.libs
po/*.gmo
po/gnome-kiosk.pot
po/*.header
po/*.sed
po/*.sin
po/.intltool-merge-cache
po/Makevars.template
po/POTFILES
po/Rules-quot
po/stamp-it
*~
*.patch
*.sw?
07070100000001000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001900000000gnome-kiosk-45.0/.gitlab07070100000002000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001C00000000gnome-kiosk-45.0/.gitlab-ci07070100000003000081A40000000000000000000000016506F4B700000688000000000000000000000000000000000000002000000000gnome-kiosk-45.0/.gitlab-ci.ymlstages:
        - build
        - test

build-fedora:
        image: registry.gitlab.gnome.org/gnome/mutter/fedora/39:x86_64-2023-08-31.0
        stage: build
        before_script:
                - .gitlab-ci/checkout-mutter.sh
                - meson mutter mutter/build --prefix=/usr
                - meson install -C mutter/build
        script:
                - export BUILD_ROOT=_build
                - meson . $BUILD_ROOT --prefix=/usr --sysconfdir=/etc --localstatedir=/var --mandir=/usr/share/man --libdir=/usr/lib64
                - ninja -C $BUILD_ROOT
                - ninja -C $BUILD_ROOT install
                - ninja -C $BUILD_ROOT dist
                - find -depth -type d -name '*.p' -exec rm -rf "{}" \;
        except:
                - tags
        artifacts:
                paths:
                        - mutter
                        - _build
        only:
            - merge_requests

test-fedora:
        image: registry.gitlab.gnome.org/gnome/mutter/fedora/39:x86_64-2023-08-31.0
        stage: test
        before_script:
                - dnf -y install patchutils
                - meson install --no-rebuild -C mutter/build
        script:
                - export BUILD_ROOT=_build
                - meson . $BUILD_ROOT --prefix=/usr --sysconfdir=/etc --localstatedir=/var --mandir=/usr/share/man --libdir=/usr/lib64
                - ninja -C $BUILD_ROOT
                - ninja -C $BUILD_ROOT test
                - find -depth -type d -name '*.p' -exec rm -rf "{}" \;
        except:
                - tags
        artifacts:
                paths:
                        - _build
        only:
            - merge_requests
07070100000004000081ED0000000000000000000000016506F4B700000618000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/.gitlab-ci/checkout-mutter.sh#!/usr/bin/bash

fetch() {
  local remote=$1
  local ref=$2

  git fetch --quiet --depth=1 $remote $ref 2>/dev/null
}

mutter_target=

echo -n Cloning into mutter ...
if git clone --quiet --depth=1 https://gitlab.gnome.org/GNOME/mutter.git; then
  echo \ done
else
  echo \ failed
  exit 1
fi

cd mutter

if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
  merge_request_remote=${CI_MERGE_REQUEST_SOURCE_PROJECT_URL//gnome-kiosk/mutter}
  merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME

  echo -n Looking for $merge_request_branch on remote ...
  if fetch $merge_request_remote $merge_request_branch; then
    echo \ found
    mutter_target=FETCH_HEAD
  else
    echo \ not found

    echo -n Looking for $CI_MERGE_REQUEST_TARGET_BRANCH_NAME instead ...
    if fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME; then
      echo \ found
      mutter_target=FETCH_HEAD
    else
      echo \ not found
    fi
  fi
fi

if [ -z "$mutter_target" ]; then
  echo -n Looking for $CI_COMMIT_REF_NAME on remote ...
  if fetch origin $CI_COMMIT_REF_NAME; then
    echo \ found
    mutter_target=FETCH_HEAD
  else
    echo \ not found
  fi
fi

fallback_branch=${CI_COMMIT_TAG:+gnome-}${CI_COMMIT_TAG%%.*}
if [ -z "$mutter_target" -a "$fallback_branch" ]; then
  echo -n Looking for $fallback_branch instead ...
  if fetch origin $fallback_branch; then
    echo \ found
    mutter_target=FETCH_HEAD
  else
    echo \ not found
  fi
fi

if [ -z "$mutter_target" ]; then
  mutter_target=HEAD
  echo Using $mutter_target instead
fi

git checkout -q $mutter_target
07070100000005000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002900000000gnome-kiosk-45.0/.gitlab/issue_templates07070100000006000081A40000000000000000000000016506F4B700000470000000000000000000000000000000000000003000000000gnome-kiosk-45.0/.gitlab/issue_templates/Bug.md<!--
Please read https://wiki.gnome.org/Community/GettingInTouch/BugReportingGuidelines
first to ensure that you create a clear and specific issue.
-->

### Affected version

<!--
Provide at least the following information:
* Your OS and version
* Affected GNOME Kiosk version
* Does this issue appear in XOrg and/or Wayland
-->

### Bug summary

<!--
Provide a short summary of the bug you encountered.
-->

### Steps to reproduce

<!--
1. Step one
2. Step two
3. ...
-->

### What happened

<!--
What did GNOME Kiosk do that was unexpected?
-->

### What did you expect to happen

<!--
What did you expect GNOME Kiosk to do?
-->

### Relevant logs, screenshots, screencasts etc.

<!--
If you have further information, such as technical documentation, logs,
screenshots or screencasts related, please provide them here.

If the bug is a crash, please obtain a stack trace with installed debug
symbols (at least for GNOME Kiosk and Mutter) and attach it to
this issue following the instructions on
https://wiki.gnome.org/Community/GettingInTouch/Bugzilla/GettingTraces.
-->


<!-- Do not remove the following line. -->
/label ~"1. Bug"
07070100000007000081A40000000000000000000000016506F4B7000002B2000000000000000000000000000000000000003400000000gnome-kiosk-45.0/.gitlab/issue_templates/Feature.md<!--
Please read https://wiki.gnome.org/Community/GettingInTouch/BugReportingGuidelines
first to ensure that you create a clear and specific issue.
-->

### Feature summary

<!--
Describe what you would like to be able to do with GNOME Kiosk
that you currently cannot do.
-->

### How would you like it to work

<!--
If you can think of a way GNOME Kiosk might be able to do this,
let us know here.
-->

### Relevant links, screenshots, screencasts etc.

<!--
If you have further information, such as technical documentation,
code, mockups or a similar feature in another desktop environments,
please provide them here.
-->


<!-- Do not remove the following line. -->
/label ~"1. Feature"
07070100000008000081A40000000000000000000000016506F4B7000046AC000000000000000000000000000000000000001900000000gnome-kiosk-45.0/COPYING                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
07070100000009000081A40000000000000000000000016506F4B700000458000000000000000000000000000000000000001600000000gnome-kiosk-45.0/NEWS# NEWS
## 45.0
- Complete port to mutter 45

## 45.rc
- Switch to gnome-desktop4
- Port to mutter 45

## 44.0
- No updates

## 44.rc
- Rename dconf profile to not have hyphen
- Set dconf profile unconditionally
- Use https instead of http in search-app

## 44.beta
- deprecation fixes
- require mutter 44
- Compat fix for Anaconda Installer project
- Script session double-starting fix
- Allow changing background in gsettings

## 43.0
- meson build fixes
- require mutter 43
- clean up code format

## 42.0
- No updates

## 42.alpha
- Port to mutter 42
- Docs fixes
- Build goo fixes

## 41.0
- Whitespace cleanup in build goo

## 41.beta
- Port to mutter 41
- New "Kiosk Script Session"
- Support systemd --user
- Neuter certain keybindings
- Crasher fix

## 40.0
- Desktop file validation fixes
- Only full screen one window at a time, not all windows
- Code clean-ups
- Support X sessions that set keyboard layout with libxklavier
- Fix crasher if localed disappears at the wrong moment

## 40.alpha
- Initial release
- Features GNOME Kiosk compositor
- Has sample search appliance
- Has demo input selector
0707010000000A000081A40000000000000000000000016506F4B700000E59000000000000000000000000000000000000001B00000000gnome-kiosk-45.0/README.md# GNOME Kiosk
## Mutter based compositor for kiosks
GNOME Kiosk provides a desktop environment suitable for fixed purpose, or
single application deployments like wall displays and point-of-sale systems.

It provides a very minimal wayland display server and compositor and Xorg
compositor and window manager. It automatically starts applications fullscreen.

Notably, GNOME Kiosk features no panels, dashes, or docks that could distract
from the application using it as a platform.

## Sample application
In order to demonstrate how GNOME Kiosk functions, there is one provided sample
application. It is a search appliance that shows https://www.google.com in a
full screen Mozilla Firefox window.

The search appliance ships with three parts:

1. A GNOME Display Manager session file that gets installed in
   `/usr/share/xsessions` and `/usr/share/wayland-sessions`.
   This file is responsible for telling the display manager how to start the
   session. It informs the display manager to start GNOME Session in a special,
   custom mode, designed specifically for setting up the kiosk environment.
1. A GNOME Session session description file that gets installed in
   `/usr/share/gnome-session/sessions`. This file is responsible for telling
   GNOME Session which components to start for the kiosk environment. The two
   components the session description file describes are GNOME Kiosk and
   Mozilla Firefox.
1. A custom application desktop file for firefox to run it in its kiosk mode pointed
   at https://www.google.com

## Keyboard layout switching
GNOME Kiosk will automatically set up the list of available keyboard layouts based
on GSettings and failing that, localed configuration.

Layout switching can be performed using the standard GNOME keybindings, which default
to Super-Space an Shift-Super-Space, and may be reconfigured using GSettings.

Because a central design ideal behind GNOME Kiosk is that it offers no persistent UI
elements, there is no builtin way aside from the above mentioned keybindings to change
keyboard layouts.

Deployments that require an on screen keyboard layout indicator need to implement it
themselves as part of their fullscreen application. GNOME Kiosk provides D-Bus APIs
to set, list, and switch between keyboard layouts.

A sample application is provided to show how these APIs function.

## Future
GNOME Kiosk is still in early development. Use cases and new ideas are actively
being considered. Some future improvements that may occur:

### On-screen keyboard
It's clear that not all target deployments where GNOME Kiosk is used will have keyboards.
It's likely that in the future GNOME Kiosk will ship with an optional on screen keyboard.

### Better input method support
At the moment GNOME Kiosk has limited support for extended methods (such as Chinese input),
using IBus. The functionality relies on IBus's own UI for selecting input candidates.

It's possible that at some point GNOME Kiosk will add some dedicated UI for input methods to
use, instead of relying on IBus's UI.

### Screen locking
One use case for GNOME Kiosk is to show a non-interactive display most of the time, but
provide a way for someone to unlock the display and interact with the application.

At the moment, it's up to the application to lock itself down, but in the future, GNOME
Kiosk may provide a transparent screen lock option, to assist the application.

## Contributing

To contribute, open merge requests at https://gitlab.gnome.org/GNOME/gnome-kiosk.

## License
GNOME Kiosk is distributed under the terms of the GNU General Public License,
version 2 or later. See the [COPYING][license] file for details.

[license]: COPYING
0707010000000B000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001C00000000gnome-kiosk-45.0/compositor0707010000000C000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002100000000gnome-kiosk-45.0/compositor/data0707010000000D000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002700000000gnome-kiosk-45.0/compositor/data/dconf0707010000000E000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000003000000000gnome-kiosk-45.0/compositor/data/dconf/defaults0707010000000F000081A40000000000000000000000016506F4B700000069000000000000000000000000000000000000004100000000gnome-kiosk-45.0/compositor/data/dconf/defaults/gnomekiosk.dconf[org/gnome/desktop/background]
color-shading-type='solid'
picture-options='none'
primary-color='#808080'
07070100000010000081A40000000000000000000000016506F4B700000043000000000000000000000000000000000000003500000000gnome-kiosk-45.0/compositor/data/dconf/gnomekiosk.inuser-db:user
file-db:@DATADIR@/@PACKAGE@/gnomekiosk.dconf.compiled
07070100000011000081A40000000000000000000000016506F4B700000173000000000000000000000000000000000000003F00000000gnome-kiosk-45.0/compositor/data/org.gnome.Kiosk.desktop.in.in[Desktop Entry]
Type=Application
Name=GNOME Kiosk
Comment=Compositor for Kiosk and Single Application deployments
Exec=@bindir@/gnome-kiosk
Categories=GNOME;GTK;Core;System;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=DisplayServer
X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=false
X-GNOME-HiddenUnderSystemd=true
07070100000012000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002900000000gnome-kiosk-45.0/compositor/data/systemd07070100000013000081A40000000000000000000000016506F4B7000000FB000000000000000000000000000000000000004000000000gnome-kiosk-45.0/compositor/data/systemd/org.gnome.Kiosk.target[Unit]
Description=GNOME Kiosk
DefaultDependencies=no

Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target

Wants=org.gnome.Kiosk@wayland.service
Wants=org.gnome.Kiosk@x11.service
07070100000014000081A40000000000000000000000016506F4B700000290000000000000000000000000000000000000004C00000000gnome-kiosk-45.0/compositor/data/systemd/org.gnome.Kiosk@wayland.service.in[Unit]
Description=GNOME Kiosk on Wayland
OnFailure=gnome-session-shutdown.target
OnFailureJobMode=replace-irreversibly
CollectMode=inactive-or-failed
RefuseManualStart=on
RefuseManualStop=on
After=gnome-session-manager.target
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
ConditionEnvironment=XDG_SESSION_TYPE=%I

[Service]
Slice=session.slice
Type=notify
ExecStart=/usr/bin/gnome-kiosk
ExecStopPost=-/bin/sh -c 'test "$SERVICE_RESULT" != "exec-condition" && systemctl --user unset-environment GNOME_SETUP_DISPLAY WAYLAND_DISPLAY DISPLAY XAUTHORITY'
Restart=no
TimeoutStopSec=5
07070100000015000081A40000000000000000000000016506F4B7000001ED000000000000000000000000000000000000004800000000gnome-kiosk-45.0/compositor/data/systemd/org.gnome.Kiosk@x11.service.in[Unit]
Description=GNOME Kiosk on X11
OnFailure=gnome-session-failed.target
OnFailureJobMode=replace
CollectMode=inactive-or-failed
RefuseManualStart=on
RefuseManualStop=on
After=gnome-session-manager.target
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
ConditionEnvironment=XDG_SESSION_TYPE=%I

[Service]
Slice=session.slice
Type=notify
ExecStart=/usr/bin/gnome-kiosk
Restart=always
RestartSec=0ms
TimeoutStopSec=5
07070100000016000081A40000000000000000000000016506F4B700003EF6000000000000000000000000000000000000003000000000gnome-kiosk-45.0/compositor/kiosk-backgrounds.c#include "config.h"
#include "kiosk-backgrounds.h"

#include <stdlib.h>
#include <string.h>

#include <clutter/clutter.h>

#include <meta/display.h>
#include <meta/util.h>

#include <meta/meta-context.h>
#include <meta/meta-backend.h>
#include <meta/meta-plugin.h>
#include <meta/meta-monitor-manager.h>
#include <meta/meta-background-actor.h>
#include <meta/meta-background-content.h>
#include <meta/meta-background-group.h>
#include <meta/meta-background-image.h>
#include <meta/meta-background.h>

#include "kiosk-compositor.h"
#include "kiosk-gobject-utils.h"

#define KIOSK_BACKGROUNDS_SCHEMA "org.gnome.desktop.background"
#define KIOSK_BACKGROUNDS_PICTURE_OPTIONS_SETTING "picture-options"
#define KIOSK_BACKGROUNDS_PICTURE_URI_SETTING "picture-uri"
#define KIOSK_BACKGROUNDS_COLOR_SHADING_TYPE_SETTING "color-shading-type"
#define KIOSK_BACKGROUNDS_PRIMARY_COLOR_SETTING "primary-color"
#define KIOSK_BACKGROUNDS_SECONDARY_COLOR_SETTING "secondary-color"

struct _KioskBackgrounds
{
        MetaBackgroundGroup       parent;

        /* weak references */
        KioskCompositor          *compositor;
        MetaDisplay              *display;
        ClutterActor             *window_group;
        MetaContext              *context;
        MetaBackend              *backend;
        MetaMonitorManager       *monitor_manager;
        ClutterActor             *stage;

        MetaBackgroundImageCache *image_cache;

        /* strong references */
        GCancellable             *cancellable;
        GSettings                *settings;
        ClutterActor             *background_group;
};

enum
{
        PROP_COMPOSITOR = 1,
        NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_backgrounds_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskBackgrounds, kiosk_backgrounds, G_TYPE_OBJECT)

static void kiosk_backgrounds_set_property (GObject      *object,
                                            guint         property_id,
                                            const GValue *value,
                                            GParamSpec   *param_spec);
static void kiosk_backgrounds_get_property (GObject    *object,
                                            guint       property_id,
                                            GValue     *value,
                                            GParamSpec *param_spec);

static void kiosk_backgrounds_constructed (GObject *object);
static void kiosk_backgrounds_dispose (GObject *object);

static void
kiosk_backgrounds_class_init (KioskBackgroundsClass *backgrounds_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (backgrounds_class);

        object_class->constructed = kiosk_backgrounds_constructed;
        object_class->set_property = kiosk_backgrounds_set_property;
        object_class->get_property = kiosk_backgrounds_get_property;
        object_class->dispose = kiosk_backgrounds_dispose;

        kiosk_backgrounds_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                             "compositor",
                                                                             "compositor",
                                                                             KIOSK_TYPE_COMPOSITOR,
                                                                             G_PARAM_CONSTRUCT_ONLY
                                                                             | G_PARAM_WRITABLE
                                                                             | G_PARAM_STATIC_NAME
                                                                             | G_PARAM_STATIC_NICK
                                                                             | G_PARAM_STATIC_BLURB);
        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_backgrounds_properties);
}

static void
set_background_color_from_settings (KioskBackgrounds *self,
                                    MetaBackground   *background)
{
        GDesktopBackgroundShading color_shading_type;
        g_autofree char *primary_color_as_string = NULL;
        g_autofree char *secondary_color_as_string = NULL;
        ClutterColor primary_color = { 0 };
        ClutterColor secondary_color = { 0 };

        color_shading_type = g_settings_get_enum (self->settings, KIOSK_BACKGROUNDS_COLOR_SHADING_TYPE_SETTING);
        primary_color_as_string = g_settings_get_string (self->settings, KIOSK_BACKGROUNDS_PRIMARY_COLOR_SETTING);
        clutter_color_from_string (&primary_color, primary_color_as_string);

        switch (color_shading_type) {
        case G_DESKTOP_BACKGROUND_SHADING_SOLID:
                meta_background_set_color (background, &primary_color);
                break;

        case G_DESKTOP_BACKGROUND_SHADING_VERTICAL:
        case G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL:
                secondary_color_as_string = g_settings_get_string (self->settings, KIOSK_BACKGROUNDS_SECONDARY_COLOR_SETTING);
                clutter_color_from_string (&secondary_color, secondary_color_as_string);
                meta_background_set_gradient (background, color_shading_type, &primary_color, &secondary_color);
                break;
        }
}

static void
on_background_image_loaded (KioskBackgrounds    *self,
                            MetaBackgroundImage *background_image)
{
        MetaBackground *background;
        GDesktopBackgroundStyle background_style;
        GFile *picture_file = NULL;

        g_signal_handlers_disconnect_by_func (G_OBJECT (background_image),
                                              on_background_image_loaded,
                                              self);

        background = g_object_get_data (G_OBJECT (background_image), "kiosk-background");

        picture_file = g_object_get_data (G_OBJECT (background), "picture-file");
        background_style = g_settings_get_enum (self->settings, KIOSK_BACKGROUNDS_PICTURE_OPTIONS_SETTING);

        meta_background_set_file (background, picture_file, background_style);
        set_background_color_from_settings (self, background);

        g_object_set_data (G_OBJECT (background), "picture-file", NULL);

        background = NULL;
        g_object_set_data (G_OBJECT (background_image), "kiosk-background", NULL);

        g_object_unref (background_image);
}

static void
set_background_file_from_settings (KioskBackgrounds *self,
                                   MetaBackground   *background)
{
        g_autofree char *uri = NULL;
        g_autoptr (GFile) picture_file = NULL;
        MetaBackgroundImage *background_image;

        uri = g_settings_get_string (self->settings, KIOSK_BACKGROUNDS_PICTURE_URI_SETTING);
        picture_file = g_file_new_for_commandline_arg (uri);

        /* We explicitly prime the file in the cache so we can defer setting the background color
         * until the image is fully loaded and avoid flicker at startup.
         */
        background_image = meta_background_image_cache_load (self->image_cache, picture_file);
        g_object_set_data_full (G_OBJECT (background_image),
                                "kiosk-background",
                                g_object_ref (background),
                                g_object_unref);
        g_object_set_data_full (G_OBJECT (background),
                                "picture-file",
                                g_steal_pointer (&picture_file),
                                g_object_unref);

        if (meta_background_image_is_loaded (background_image)) {
                kiosk_gobject_utils_queue_immediate_callback (G_OBJECT (self),
                                                              "[kiosk-backgrounds] on_background_image_loaded",
                                                              self->cancellable,
                                                              KIOSK_OBJECT_CALLBACK (on_background_image_loaded),
                                                              background);
        } else {
                g_signal_connect_object (G_OBJECT (background_image),
                                         "loaded",
                                         G_CALLBACK (on_background_image_loaded),
                                         self,
                                         G_CONNECT_SWAPPED);
        }
}

static void
create_background_for_monitor (KioskBackgrounds *self,
                               int               monitor_index)
{
        g_autoptr (MetaBackground) background = NULL;
        GDesktopBackgroundStyle background_style;
        MtkRectangle geometry;
        ClutterActor *background_actor = NULL;
        MetaBackgroundContent *background_content;

        g_debug ("KioskBackgrounds: Creating background for monitor %d", monitor_index);

        background = meta_background_new (self->display);
        background_style = g_settings_get_enum (self->settings, KIOSK_BACKGROUNDS_PICTURE_OPTIONS_SETTING);

        if (background_style == G_DESKTOP_BACKGROUND_STYLE_NONE) {
                set_background_color_from_settings (self, background);
        } else {
                set_background_file_from_settings (self, background);
        }

        background_actor = meta_background_actor_new (self->display, monitor_index);

        meta_display_get_monitor_geometry (self->display, monitor_index, &geometry);

        clutter_actor_set_position (background_actor, geometry.x, geometry.y);
        clutter_actor_set_size (background_actor, geometry.width, geometry.height);

        background_content = META_BACKGROUND_CONTENT (clutter_actor_get_content (background_actor));
        meta_background_content_set_background (background_content, background);

        clutter_actor_add_child (self->background_group, background_actor);
        clutter_actor_show (background_actor);
}

static void
reinitialize_backgrounds (KioskBackgrounds *self)
{
        int i, number_of_monitors;

        g_debug ("KioskBackgrounds: Recreating backgrounds");

        clutter_actor_destroy_all_children (self->background_group);

        number_of_monitors = meta_display_get_n_monitors (self->display);
        for (i = 0; i < number_of_monitors; i++) {
                create_background_for_monitor (self, i);
        }

        g_debug ("KioskBackgrounds: Finished recreating backgrounds");
}

static void
kiosk_backgrounds_set_property (GObject      *object,
                                guint         property_id,
                                const GValue *value,
                                GParamSpec   *param_spec)
{
        KioskBackgrounds *self = KIOSK_BACKGROUNDS (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;

        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_backgrounds_get_property (GObject    *object,
                                guint       property_id,
                                GValue     *value,
                                GParamSpec *param_spec)
{
        switch (property_id) {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_backgrounds_dispose (GObject *object)
{
        KioskBackgrounds *self = KIOSK_BACKGROUNDS (object);
        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        g_clear_object (&self->background_group);
        g_clear_object (&self->settings);

        g_clear_weak_pointer (&self->context);
        g_clear_weak_pointer (&self->backend);
        g_clear_weak_pointer (&self->stage);
        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->window_group);
        g_clear_weak_pointer (&self->monitor_manager);
        g_clear_weak_pointer (&self->compositor);
        g_clear_weak_pointer (&self->image_cache);

        G_OBJECT_CLASS (kiosk_backgrounds_parent_class)->dispose (object);
}

static void
on_settings_changed (KioskBackgrounds *self)
{
        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-backgrounds] on_backgrounds_settings_changed",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (reinitialize_backgrounds),
                                                  NULL);
}

static void
kiosk_backgrounds_constructed (GObject *object)
{
        KioskBackgrounds *self = KIOSK_BACKGROUNDS (object);

        G_OBJECT_CLASS (kiosk_backgrounds_parent_class)->constructed (object);

        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
        g_set_weak_pointer (&self->backend, meta_context_get_backend (self->context));
        g_set_weak_pointer (&self->stage, meta_get_stage_for_display (self->display));
        g_set_weak_pointer (&self->window_group, meta_get_window_group_for_display (self->display));
        g_set_weak_pointer (&self->monitor_manager, meta_backend_get_monitor_manager (self->backend));
        g_set_weak_pointer (&self->image_cache, meta_background_image_cache_get_default ());

        self->cancellable = g_cancellable_new ();

        self->background_group = meta_background_group_new ();
        clutter_actor_insert_child_below (self->window_group, self->background_group, NULL);

        g_signal_connect_object (G_OBJECT (self->monitor_manager),
                                 "monitors-changed",
                                 G_CALLBACK (reinitialize_backgrounds),
                                 self,
                                 G_CONNECT_SWAPPED);

        self->settings = g_settings_new (KIOSK_BACKGROUNDS_SCHEMA);

        g_signal_connect_object (G_OBJECT (self->settings),
                                 "changed::" KIOSK_BACKGROUNDS_PICTURE_OPTIONS_SETTING,
                                 G_CALLBACK (on_settings_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->settings),
                                 "changed::" KIOSK_BACKGROUNDS_PICTURE_URI_SETTING,
                                 G_CALLBACK (on_settings_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->settings),
                                 "changed::" KIOSK_BACKGROUNDS_COLOR_SHADING_TYPE_SETTING,
                                 G_CALLBACK (on_settings_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->settings),
                                 "changed::" KIOSK_BACKGROUNDS_PRIMARY_COLOR_SETTING,
                                 G_CALLBACK (on_settings_changed),
                                 self,
                                 G_CONNECT_SWAPPED);

        g_signal_connect_object (G_OBJECT (self->settings),
                                 "changed::" KIOSK_BACKGROUNDS_SECONDARY_COLOR_SETTING,
                                 G_CALLBACK (on_settings_changed),
                                 self,
                                 G_CONNECT_SWAPPED);

        reinitialize_backgrounds (self);
}

static void
kiosk_backgrounds_init (KioskBackgrounds *self)
{
        g_debug ("KioskBackgrounds: Initializing");
}

KioskBackgrounds *
kiosk_backgrounds_new (KioskCompositor *compositor)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_BACKGROUNDS,
                               "compositor", compositor,
                               NULL);

        return KIOSK_BACKGROUNDS (object);
}
07070100000017000081A40000000000000000000000016506F4B7000001CD000000000000000000000000000000000000003000000000gnome-kiosk-45.0/compositor/kiosk-backgrounds.h#pragma once

#include <glib-object.h>
#include <meta/meta-background-group.h>

typedef struct _KioskCompositor KioskCompositor;

G_BEGIN_DECLS

#define KIOSK_TYPE_BACKGROUNDS (kiosk_backgrounds_get_type ())

G_DECLARE_FINAL_TYPE (KioskBackgrounds,
                      kiosk_backgrounds,
                      KIOSK, BACKGROUNDS,
                      MetaBackgroundGroup);

KioskBackgrounds *kiosk_backgrounds_new (KioskCompositor *compositor);

G_END_DECLS
07070100000018000081A40000000000000000000000016506F4B700004F7D000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/compositor/kiosk-compositor.c#include "config.h"
#include "kiosk-compositor.h"

#include <stdlib.h>
#include <string.h>

#include <glib-object.h>

#include <clutter/clutter.h>
#include <meta/common.h>
#include <meta/display.h>
#include <meta/keybindings.h>
#include <meta/meta-context.h>
#include <meta/util.h>
#include <meta/meta-window-group.h>

#include <systemd/sd-daemon.h>

#include "kiosk-backgrounds.h"
#include "kiosk-gobject-utils.h"
#include "kiosk-input-sources-manager.h"
#include "kiosk-service.h"

#include "org.gnome.DisplayManager.Manager.h"

struct _KioskCompositor
{
        MetaPlugin                parent;

        /* weak references */
        MetaDisplay              *display;
        MetaContext              *context;
        ClutterBackend           *backend;
        ClutterActor             *stage;

        /* strong references */
        GCancellable             *cancellable;
        KioskBackgrounds         *backgrounds;
        KioskInputSourcesManager *input_sources_manager;
        KioskService             *service;
};

enum
{
        X_SERVER_EVENT,
        NUMBER_OF_SIGNALS
};

static guint signals[NUMBER_OF_SIGNALS] = { 0, };

G_DEFINE_TYPE (KioskCompositor, kiosk_compositor, META_TYPE_PLUGIN)

static void kiosk_compositor_dispose (GObject *object);

static void
kiosk_compositor_dispose (GObject *object)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (object);

        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        g_clear_weak_pointer (&self->stage);
        g_clear_weak_pointer (&self->context);
        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->backend);

        g_clear_object (&self->backgrounds);

        G_OBJECT_CLASS (kiosk_compositor_parent_class)->dispose (object);
}

static void
register_with_display_manager (KioskCompositor *self)
{
        g_autoptr (GDBusConnection) system_bus = NULL;
        g_autoptr (GdmManager) display_manager = NULL;
        GVariantBuilder builder;
        g_autoptr (GError) error = NULL;
        g_autoptr (GVariant) reply = NULL;

        system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
                                     self->cancellable,
                                     &error);
        if (error != NULL) {
                g_debug ("KioskCompositor: Could not contact system bus: %s",
                         error->message);
                return;
        }

        display_manager = gdm_manager_proxy_new_sync (system_bus,
                                                      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                                      G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                                      "org.gnome.DisplayManager",
                                                      "/org/gnome/DisplayManager/Manager",
                                                      self->cancellable,
                                                      &error);

        if (error != NULL) {
                g_debug ("KioskCompositor: Could not contact display manager: %s",
                         error->message);
                return;
        }

        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));

        gdm_manager_call_register_display_sync (display_manager,
                                                g_variant_builder_end (&builder),
                                                self->cancellable,
                                                &error);

        if (error != NULL) {
                g_debug ("KioskCompositor: Could not register with display manager: %s",
                         error->message);
                return;
        }
}

static void
register_with_systemd (KioskCompositor *self)
{
        sd_notify (TRUE, "READY=1");
}

static void
register_session (KioskCompositor *self)
{
        meta_context_notify_ready (self->context);

        register_with_display_manager (self);

        register_with_systemd (self);
}

static void
on_builtin_keybinding_triggered (MetaDisplay     *display,
                                 MetaWindow      *window,
                                 ClutterKeyEvent *event,
                                 MetaKeyBinding  *binding,
                                 KioskCompositor *self)
{
        g_debug ("KioskCompositor: Ignoring '%s' request",
                 meta_key_binding_get_name (binding));
}

static void
neuter_builtin_keybindings (KioskCompositor *self)
{
        const char *builtin_keybindings[] = {
                "switch-to-workspace-1",
                "switch-to-workspace-2",
                "switch-to-workspace-3",
                "switch-to-workspace-4",
                "switch-to-workspace-5",
                "switch-to-workspace-6",
                "switch-to-workspace-7",
                "switch-to-workspace-8",
                "switch-to-workspace-9",
                "switch-to-workspace-10",
                "switch-to-workspace-11",
                "switch-to-workspace-12",
                "switch-to-workspace-left",
                "switch-to-workspace-right",
                "switch-to-workspace-up",
                "switch-to-workspace-down",
                "switch-to-workspace-last",
                "panel-main-menu",
                "panel-run-dialog",
                "set-spew-mark",
                "switch-monitor",
                "rotate-monitor",
                "restore-shortcuts",
                "activate-window-menu",
                "toggle-above",
                "toggle-shaded",
                "minimize",
                "toggle-on-all-workspaces",
                "move-to-workspace-1",
                "move-to-workspace-2",
                "move-to-workspace-3",
                "move-to-workspace-4",
                "move-to-workspace-5",
                "move-to-workspace-6",
                "move-to-workspace-7",
                "move-to-workspace-8",
                "move-to-workspace-9",
                "move-to-workspace-10",
                "move-to-workspace-11",
                "move-to-workspace-12",
                "move-to-workspace-last",
                "move-to-workspace-left",
                "move-to-workspace-right",
                "move-to-workspace-up",
                "move-to-workspace-down",
                NULL
        };
        size_t i;

        g_debug ("KioskCompositor: Neutering builtin keybindings");

        for (i = 0; builtin_keybindings[i] != NULL; i++) {
                meta_keybindings_set_custom_handler (builtin_keybindings[i],
                                                     (MetaKeyHandlerFunc)
                                                     on_builtin_keybinding_triggered,
                                                     self,
                                                     NULL);
        }
}

static void
kiosk_compositor_start (MetaPlugin *plugin)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);
        g_autoptr (GError) error = NULL;

        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self)));
        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
        g_set_weak_pointer (&self->backend, clutter_get_default_backend ());
        g_set_weak_pointer (&self->stage, meta_get_stage_for_display (self->display));

        clutter_actor_show (self->stage);

        self->cancellable = g_cancellable_new ();

        self->service = kiosk_service_new (self);
        kiosk_service_start (self->service, &error);

        if (error != NULL) {
                g_debug ("KioskCompositor: Could not start D-Bus service: %s", error->message);
                g_clear_error (&error);
        }

        neuter_builtin_keybindings (self);

        self->backgrounds = kiosk_backgrounds_new (self);
        self->input_sources_manager = kiosk_input_sources_manager_new (self);

        kiosk_gobject_utils_queue_immediate_callback (G_OBJECT (self),
                                                      "[kiosk-compositor] register_session",
                                                      self->cancellable,
                                                      KIOSK_OBJECT_CALLBACK (register_session),
                                                      NULL);
}

static void
kiosk_compositor_minimize (MetaPlugin      *plugin,
                           MetaWindowActor *actor)
{
        meta_plugin_minimize_completed (plugin, actor);
}

static void
kiosk_compositor_unminimize (MetaPlugin      *plugin,
                             MetaWindowActor *actor)
{
        meta_plugin_unminimize_completed (plugin, actor);
}

static void
kiosk_compositor_size_changed (MetaPlugin      *plugin,
                               MetaWindowActor *actor)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->size_changed == NULL);
}

static void
kiosk_compositor_size_change (MetaPlugin      *plugin,
                              MetaWindowActor *actor,
                              MetaSizeChange   which_change,
                              MtkRectangle    *old_frame_rect,
                              MtkRectangle    *old_buffer_rect)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->size_change == NULL);
}

static gboolean
kiosk_compositor_wants_window_fullscreen (KioskCompositor *self,
                                          MetaWindow      *window)
{
        MetaWindowType window_type;

        g_autoptr (GList) windows = NULL;
        GList *node;

        if (!meta_window_allows_resize (window)) {
                g_debug ("KioskCompositor: Window does not allow resizes");
                return FALSE;
        }

        if (meta_window_is_override_redirect (window)) {
                g_debug ("KioskCompositor: Window is override redirect");
                return FALSE;
        }

        window_type = meta_window_get_window_type (window);

        if (window_type != META_WINDOW_NORMAL) {
                g_debug ("KioskCompositor: Window is not normal");
                return FALSE;
        }

        windows = meta_display_get_tab_list (self->display, META_TAB_LIST_NORMAL_ALL, NULL);

        for (node = windows; node != NULL; node = node->next) {
                MetaWindow *existing_window = node->data;

                if (meta_window_is_monitor_sized (existing_window)) {
                        return FALSE;
                }
        }

        return TRUE;
}

static gboolean
kiosk_compositor_wants_window_above (KioskCompositor *self,
                                     MetaWindow      *window)
{
        if (meta_window_is_screen_sized (window)) {
                return FALSE;
        }

        if (meta_window_is_monitor_sized (window)) {
                return FALSE;
        }

        return TRUE;
}

static void
on_faded_in (KioskCompositor   *self,
             ClutterTransition *transition)
{
        MetaWindowActor *actor = g_object_get_data (G_OBJECT (transition), "actor");

        meta_plugin_map_completed (META_PLUGIN (self), actor);
}

static void
kiosk_compositor_map (MetaPlugin      *plugin,
                      MetaWindowActor *actor)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);
        MetaWindow *window;
        ClutterTransition *fade_in_transition;
        int easing_duration;

        window = meta_window_actor_get_meta_window (actor);

        if (kiosk_compositor_wants_window_fullscreen (self, window)) {
                g_debug ("KioskCompositor: Mapping window that does need to be fullscreened");
                meta_window_make_fullscreen (window);
                easing_duration = 3000;
        } else {
                ClutterActor *window_group;

                g_debug ("KioskCompositor: Mapping window that does not need to be fullscreened");
                window_group = meta_get_top_window_group_for_display (self->display);

                if (kiosk_compositor_wants_window_above (self, window)) {
                        g_object_ref (G_OBJECT (actor));
                        clutter_actor_remove_child (clutter_actor_get_parent (CLUTTER_ACTOR (actor)), CLUTTER_ACTOR (actor));
                        clutter_actor_add_child (window_group, CLUTTER_ACTOR (actor));
                        clutter_actor_set_child_above_sibling (window_group, CLUTTER_ACTOR (actor), NULL);
                        g_object_unref (G_OBJECT (actor));
                }

                easing_duration = 500;
        }

        clutter_actor_show (self->stage);
        clutter_actor_show (CLUTTER_ACTOR (actor));

        clutter_actor_set_opacity (CLUTTER_ACTOR (actor), 0);

        clutter_actor_save_easing_state (CLUTTER_ACTOR (actor));
        clutter_actor_set_easing_duration (CLUTTER_ACTOR (actor), easing_duration);
        clutter_actor_set_easing_mode (CLUTTER_ACTOR (actor), CLUTTER_EASE_IN_OUT_QUINT);
        clutter_actor_set_opacity (CLUTTER_ACTOR (actor), 255);
        fade_in_transition = clutter_actor_get_transition (CLUTTER_ACTOR (actor), "opacity");
        clutter_actor_restore_easing_state (CLUTTER_ACTOR (actor));

        g_object_set_data (G_OBJECT (fade_in_transition), "actor", actor);

        g_signal_connect_object (G_OBJECT (fade_in_transition),
                                 "completed",
                                 G_CALLBACK (on_faded_in),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
kiosk_compositor_destroy (MetaPlugin      *plugin,
                          MetaWindowActor *actor)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);

        clutter_actor_hide (CLUTTER_ACTOR (actor));

        meta_plugin_destroy_completed (META_PLUGIN (self), actor);
}

static void
kiosk_compositor_switch_workspace (MetaPlugin          *plugin,
                                   gint                 from,
                                   gint                 to,
                                   MetaMotionDirection  direction)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);

        meta_plugin_switch_workspace_completed (META_PLUGIN (self));
}

static void
kiosk_compositor_kill_window_effects (MetaPlugin      *plugin,
                                      MetaWindowActor *actor)
{
}

static void
kiosk_compositor_kill_switch_workspace (MetaPlugin *plugin)
{
}

static void
kiosk_compositor_show_tile_preview (MetaPlugin    *plugin,
                                    MetaWindow    *window,
                                    MtkRectangle  *tile_rect,
                                    int            tile_monitor)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_tile_preview == NULL);
}

static void
kiosk_compositor_hide_tile_preview (MetaPlugin *plugin)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->hide_tile_preview == NULL);
}

static void
kiosk_compositor_show_window_menu (MetaPlugin         *plugin,
                                   MetaWindow         *window,
                                   MetaWindowMenuType  menu,
                                   int                 x,
                                   int                 y)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_window_menu == NULL);
}

static void
kiosk_compositor_show_window_menu_for_rect (MetaPlugin         *plugin,
                                            MetaWindow         *window,
                                            MetaWindowMenuType  menu,
                                            MtkRectangle       *rect)
{
        g_assert (META_PLUGIN_CLASS (kiosk_compositor_parent_class)->show_window_menu_for_rect == NULL);
}

static gboolean
kiosk_compositor_xevent_filter (MetaPlugin *plugin,
                                XEvent     *x_server_event)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);

        g_signal_emit (G_OBJECT (self), signals[X_SERVER_EVENT], 0, x_server_event);
        return FALSE;
}

static gboolean
kiosk_compositor_keybinding_filter (MetaPlugin     *plugin,
                                    MetaKeyBinding *binding)
{
        return FALSE;
}

static void
kiosk_compositor_confirm_display_change (MetaPlugin *plugin)
{
        KioskCompositor *self = KIOSK_COMPOSITOR (plugin);

        meta_plugin_complete_display_change (META_PLUGIN (self), TRUE);
}

static const MetaPluginInfo info = {
        .name        = "GNOME Kiosk",
        .version     = VERSION,
        .author      = "Various",
        .license     = "GPLv2+",
        .description = "Provides Kiosk compositor plugin for mutter"
};

static const MetaPluginInfo *
kiosk_compositor_plugin_info (MetaPlugin *plugin)
{
        return &info;
}

static MetaCloseDialog *
kiosk_compositor_create_close_dialog (MetaPlugin *plugin,
                                      MetaWindow *window)
{
        return NULL;
}

static MetaInhibitShortcutsDialog *
kiosk_compositor_create_inhibit_shortcuts_dialog (MetaPlugin *plugin,
                                                  MetaWindow *window)
{
        return NULL;
}

static void
kiosk_compositor_locate_pointer (MetaPlugin *plugin)
{
}

static void
kiosk_compositor_class_init (KioskCompositorClass *compositor_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (compositor_class);
        MetaPluginClass *plugin_class = META_PLUGIN_CLASS (compositor_class);

        object_class->dispose = kiosk_compositor_dispose;

        plugin_class->start = kiosk_compositor_start;
        plugin_class->map = kiosk_compositor_map;
        plugin_class->minimize = kiosk_compositor_minimize;
        plugin_class->unminimize = kiosk_compositor_unminimize;
        plugin_class->size_changed = kiosk_compositor_size_changed;
        plugin_class->size_change = kiosk_compositor_size_change;
        plugin_class->destroy = kiosk_compositor_destroy;

        plugin_class->switch_workspace = kiosk_compositor_switch_workspace;

        plugin_class->kill_window_effects = kiosk_compositor_kill_window_effects;
        plugin_class->kill_switch_workspace = kiosk_compositor_kill_switch_workspace;

        plugin_class->show_tile_preview = kiosk_compositor_show_tile_preview;
        plugin_class->hide_tile_preview = kiosk_compositor_hide_tile_preview;
        plugin_class->show_window_menu = kiosk_compositor_show_window_menu;
        plugin_class->show_window_menu_for_rect = kiosk_compositor_show_window_menu_for_rect;

        plugin_class->xevent_filter = kiosk_compositor_xevent_filter;
        plugin_class->keybinding_filter = kiosk_compositor_keybinding_filter;

        plugin_class->confirm_display_change = kiosk_compositor_confirm_display_change;

        plugin_class->plugin_info = kiosk_compositor_plugin_info;

        plugin_class->create_close_dialog = kiosk_compositor_create_close_dialog;
        plugin_class->create_inhibit_shortcuts_dialog = kiosk_compositor_create_inhibit_shortcuts_dialog;

        plugin_class->locate_pointer = kiosk_compositor_locate_pointer;

        signals [X_SERVER_EVENT] =
                g_signal_new ("x-server-event",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL,
                              NULL,
                              g_cclosure_marshal_VOID__POINTER,
                              G_TYPE_NONE,
                              1, G_TYPE_POINTER);
}

static void
kiosk_compositor_init (KioskCompositor *compositor)
{
        g_debug ("KioskCompositor: Initializing");
}

KioskBackgrounds *
kiosk_compositor_get_backgrounds (KioskCompositor *self)
{
        g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL);

        return KIOSK_BACKGROUNDS (self->backgrounds);
}

KioskInputSourcesManager *
kiosk_compositor_get_input_sources_manager (KioskCompositor *self)
{
        g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL);

        return KIOSK_INPUT_SOURCES_MANAGER (self->input_sources_manager);
}

KioskService *
kiosk_compositor_get_service (KioskCompositor *self)
{
        g_return_val_if_fail (KIOSK_IS_COMPOSITOR (self), NULL);

        return KIOSK_SERVICE (self->service);
}
07070100000019000081A40000000000000000000000016506F4B700000288000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/compositor/kiosk-compositor.h#pragma once

#include <glib-object.h>
#include <meta/meta-plugin.h>

#include "kiosk-backgrounds.h"
#include "kiosk-input-sources-manager.h"
#include "kiosk-service.h"

G_BEGIN_DECLS
#define KIOSK_TYPE_COMPOSITOR (kiosk_compositor_get_type ())

G_DECLARE_FINAL_TYPE (KioskCompositor, kiosk_compositor,
                      KIOSK, COMPOSITOR,
                      MetaPlugin);

KioskBackgrounds *kiosk_compositor_get_backgrounds (KioskCompositor *compositor);
KioskInputSourcesManager *kiosk_compositor_get_input_sources_manager (KioskCompositor *compositor);
KioskService *kiosk_compositor_get_service (KioskCompositor *compositor);
G_END_DECLS
0707010000001A000081A40000000000000000000000016506F4B7000014DA000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/compositor/kiosk-dbus-utils.c#include "config.h"
#include "kiosk-dbus-utils.h"

#include <string.h>

#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gio/gio.h>

char *
kiosk_dbus_utils_escape_object_path (const char *data,
                                     gsize       length)
{
        const char *p;
        char *object_path;
        GString *string;

        g_return_val_if_fail (data != NULL, NULL);

        string = g_string_sized_new ((length + 1) * 6);

        for (p = data; *p != '\0'; p++) {
                guchar character;

                character = (guchar) * p;

                if (((character >= ((guchar) 'a')) &&
                     (character <= ((guchar) 'z'))) ||
                    ((character >= ((guchar) 'A')) &&
                     (character <= ((guchar) 'Z'))) ||
                    ((character >= ((guchar) '0')) && (character <= ((guchar) '9')))) {
                        g_string_append_c (string, (char) character);
                        continue;
                }

                g_string_append_printf (string, "_%x_", character);
        }

        object_path = string->str;

        g_string_free (string, FALSE);

        return object_path;
}

static char *
dashed_string_to_studly_caps (const char *dashed_string)
{
        char *studly_string;
        size_t studly_string_length;
        size_t i;

        i = 0;

        studly_string = g_strdup (dashed_string);
        studly_string_length = strlen (studly_string);

        studly_string[i] = g_ascii_toupper (studly_string[i]);
        i++;

        while (i < studly_string_length) {
                if (studly_string[i] == '-' || studly_string[i] == '_') {
                        memmove (studly_string + i, studly_string + i + 1, studly_string_length - i - 1);
                        studly_string_length--;
                        if (g_ascii_isalpha (studly_string[i])) {
                                studly_string[i] = g_ascii_toupper (studly_string[i]);
                        }
                }
                i++;
        }
        studly_string[studly_string_length] = '\0';

        return studly_string;
}

static char *
dashed_string_to_dbus_error_string (const char *dashed_string,
                                    const char *old_prefix,
                                    const char *new_prefix,
                                    const char *suffix)
{
        char *studly_suffix;
        char *dbus_error_string;
        size_t dbus_error_string_length;
        size_t i;

        i = 0;

        if (g_str_has_prefix (dashed_string, old_prefix) &&
            (dashed_string[strlen (old_prefix)] == '-' ||
             dashed_string[strlen (old_prefix)] == '_')) {
                dashed_string += strlen (old_prefix) + 1;
        }

        studly_suffix = dashed_string_to_studly_caps (suffix);
        dbus_error_string = g_strdup_printf ("%s.%s.%s",
                                             new_prefix,
                                             dashed_string,
                                             studly_suffix);
        g_free (studly_suffix);
        i += strlen (new_prefix) + 1;

        dbus_error_string_length = strlen (dbus_error_string);

        dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]);
        i++;

        while (i < dbus_error_string_length) {
                if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') {
                        dbus_error_string[i] = '.';

                        if (g_ascii_isalpha (dbus_error_string[i + 1])) {
                                dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]);
                        }
                }

                i++;
        }

        return dbus_error_string;
}

void
kiosk_dbus_utils_register_error_domain (GQuark  error_domain,
                                        GType   error_enum)
{
        const char *error_domain_string;
        g_autofree char *type_name = NULL;
        GType type;
        g_autoptr (GTypeClass) type_class = NULL;
        const GEnumClass *enum_class;
        guint i;

        error_domain_string = g_quark_to_string (error_domain);
        type_name = dashed_string_to_studly_caps (error_domain_string);
        type = g_type_from_name (type_name);
        type_class = g_type_class_ref (type);

        if (type_class == NULL) {
                g_warning ("kiosk-dbus-utils: Could not identify type %s", type_name);
                return;
        }

        enum_class = G_ENUM_CLASS (type_class);

        for (i = 0; i < enum_class->n_values; i++) {
                g_autofree char *dbus_error_string = NULL;

                dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string,
                                                                        "kiosk",
                                                                        "org.gnome",
                                                                        enum_class->values[i].
                                                                        value_nick);

                g_debug ("kiosk-dbus-utils: Registering dbus error %s", dbus_error_string);
                g_dbus_error_register_error (error_domain,
                                             enum_class->values[i].value, dbus_error_string);
        }
}
0707010000001B000081A40000000000000000000000016506F4B70000019D000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/compositor/kiosk-dbus-utils.h#ifndef KIOSK_DBUS_UTILS_H
#define KIOSK_DBUS_UTILS_H

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

G_BEGIN_DECLS

void kiosk_dbus_utils_register_error_domain (GQuark  error_domain,
                                             GType   error_enum);

char *kiosk_dbus_utils_escape_object_path (const char *data,
                                           gsize       length);
G_END_DECLS
#endif
0707010000001C000081A40000000000000000000000016506F4B700000FD7000000000000000000000000000000000000003200000000gnome-kiosk-45.0/compositor/kiosk-gobject-utils.c#include "config.h"
#include "kiosk-gobject-utils.h"

#define COALESCE_INTERVAL 250 /* milliseconds */

static void
on_task_wait_complete (GObject *self,
                       GTask   *task)
{
        KioskObjectCallback callback;
        gpointer user_data;
        gboolean completed;
        g_autofree char *data_key = NULL;

        g_debug ("KioskGObjectUtils: Executing queued task '%s'", g_task_get_name (task));

        callback = g_object_get_data (G_OBJECT (task), "callback");
        user_data = g_object_get_data (G_OBJECT (task), "user-data");

        completed = g_task_propagate_boolean (task, NULL);

        if (completed) {
                callback (self, user_data);
        }

        data_key = g_strdup_printf ("kiosk-gobject-utils-%p-%p-task",
                                    callback, user_data);

        g_object_set_data (G_OBJECT (self), data_key, NULL);
}

static gboolean
on_called_back (GTask *task)
{
        if (!g_task_return_error_if_cancelled (task)) {
                g_task_return_boolean (task, TRUE);
        }

        return G_SOURCE_REMOVE;
}

static void
kiosk_gobject_utils_queue_callback (GObject             *self,
                                    const char          *name,
                                    int                  timeout,
                                    GCancellable        *cancellable,
                                    KioskObjectCallback  callback,
                                    gpointer             user_data)
{
        g_autofree char *data_key = NULL;
        g_autoptr (GSource) source = NULL;
        GTask *task;

        g_return_if_fail (G_IS_OBJECT (self));
        g_return_if_fail (callback != NULL);

        data_key = g_strdup_printf ("kiosk-gobject-utils-%p-%p-task",
                                    callback, user_data);

        task = g_object_get_data (G_OBJECT (self), data_key);

        if (task != NULL) {
                return;
        }

        if (timeout <= 0)
                source = g_idle_source_new ();
        else
                source = g_timeout_source_new (timeout);

        task = g_task_new (self,
                           cancellable,
                           (GAsyncReadyCallback) on_task_wait_complete,
                           NULL);

        if (name != NULL) {
                g_task_set_name (task, name);

                if (timeout > 0)
                        g_debug ("KioskGObjectUtils: Deferring task '%s' for %dms", name, timeout);
                else
                        g_debug ("KioskGObjectUtils: Queuing task '%s' to run on next iteration of event loop", name);
        }

        g_task_attach_source (task, source, G_SOURCE_FUNC (on_called_back));

        g_object_set_data (G_OBJECT (task), "callback", callback);
        g_object_set_data (G_OBJECT (task), "user-data", user_data);

        g_object_set_data_full (G_OBJECT (self),
                                data_key,
                                task,
                                (GDestroyNotify)
                                g_object_unref);
}

void
kiosk_gobject_utils_queue_defer_callback (GObject             *self,
                                          const char          *name,
                                          GCancellable        *cancellable,
                                          KioskObjectCallback  callback,
                                          gpointer             user_data)
{
        kiosk_gobject_utils_queue_callback (self, name, COALESCE_INTERVAL, cancellable, callback, user_data);
}

void
kiosk_gobject_utils_queue_immediate_callback (GObject             *self,
                                              const char          *name,
                                              GCancellable        *cancellable,
                                              KioskObjectCallback  callback,
                                              gpointer             user_data)
{
        kiosk_gobject_utils_queue_callback (self, name, 0, cancellable, callback, user_data);
}
0707010000001D000081A40000000000000000000000016506F4B700000443000000000000000000000000000000000000003200000000gnome-kiosk-45.0/compositor/kiosk-gobject-utils.h#pragma once

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

G_BEGIN_DECLS

typedef void (* KioskObjectCallback) (GObject  *self,
                                      gpointer  user_data);
#define KIOSK_OBJECT_CALLBACK(_callback) ((KioskObjectCallback) _callback)

void kiosk_gobject_utils_queue_defer_callback (GObject             *self,
                                               const char          *name,
                                               GCancellable        *cancellable,
                                               KioskObjectCallback  callback,
                                               gpointer             user_data);
void kiosk_gobject_utils_queue_immediate_callback (GObject             *self,
                                                   const char          *name,
                                                   GCancellable        *cancellable,
                                                   KioskObjectCallback  callback,
                                                   gpointer             user_data);

G_END_DECLS
0707010000001E000081A40000000000000000000000016506F4B700005505000000000000000000000000000000000000003900000000gnome-kiosk-45.0/compositor/kiosk-input-engine-manager.c#include "config.h"
#include "kiosk-input-engine-manager.h"

#include <stdlib.h>
#include <string.h>

#include <ibus.h>

#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>

#include <meta/display.h>
#include <meta/util.h>

#include <meta/meta-backend.h>

#include "org.gnome.SessionManager.h"

#include "kiosk-gobject-utils.h"
#include "kiosk-input-sources-manager.h"

#define DEFAULT_INPUT_ENGINE_NAME "xkb:us::eng"
#define DEFAULT_LAYOUT_NAME "us"

struct _KioskInputEngineManager
{
        GObject                   parent;

        /* weak references */
        KioskInputSourcesManager *input_sources_manager;

        /* strong references */
        GCancellable             *cancellable;
        IBusBus                  *bus;
        GHashTable               *engines;
        char                     *active_engine;

        /* state */
        guint32                   is_loaded : 1;
};

enum
{
        PROP_INPUT_SOURCES_MANAGER = 1,
        PROP_IS_LOADED,
        PROP_ACTIVE_ENGINE,
        NUMBER_OF_PROPERTIES
};

static GParamSpec *kiosk_input_engine_manager_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskInputEngineManager, kiosk_input_engine_manager, G_TYPE_OBJECT)

static void kiosk_input_engine_manager_set_property (GObject      *object,
                                                     guint         property_id,
                                                     const GValue *value,
                                                     GParamSpec   *param_spec);
static void kiosk_input_engine_manager_get_property (GObject    *object,
                                                     guint       property_id,
                                                     GValue     *value,
                                                     GParamSpec *param_spec);

static void kiosk_input_engine_manager_constructed (GObject *object);
static void kiosk_input_engine_manager_dispose (GObject *object);

KioskInputEngineManager *
kiosk_input_engine_manager_new (KioskInputSourcesManager *input_sources_manager)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_INPUT_ENGINE_MANAGER,
                               "input-sources-manager", input_sources_manager,
                               NULL);

        return KIOSK_INPUT_ENGINE_MANAGER (object);
}

static void
kiosk_input_engine_manager_class_init (KioskInputEngineManagerClass *input_engine_manager_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (input_engine_manager_class);

        object_class->constructed = kiosk_input_engine_manager_constructed;
        object_class->set_property = kiosk_input_engine_manager_set_property;
        object_class->get_property = kiosk_input_engine_manager_get_property;
        object_class->dispose = kiosk_input_engine_manager_dispose;

        kiosk_input_engine_manager_properties[PROP_INPUT_SOURCES_MANAGER] = g_param_spec_object ("input-sources-manager",
                                                                                                 "input-sources-manager",
                                                                                                 "input-sources-manager",
                                                                                                 KIOSK_TYPE_INPUT_SOURCES_MANAGER,
                                                                                                 G_PARAM_CONSTRUCT_ONLY
                                                                                                 | G_PARAM_WRITABLE
                                                                                                 | G_PARAM_STATIC_NAME
                                                                                                 | G_PARAM_STATIC_NICK
                                                                                                 | G_PARAM_STATIC_BLURB);
        kiosk_input_engine_manager_properties[PROP_IS_LOADED] = g_param_spec_boolean ("is-loaded",
                                                                                      "is-loaded",
                                                                                      "is-loaded",
                                                                                      FALSE,
                                                                                      G_PARAM_READABLE
                                                                                      | G_PARAM_STATIC_NAME
                                                                                      | G_PARAM_STATIC_NICK
                                                                                      | G_PARAM_STATIC_BLURB);

        kiosk_input_engine_manager_properties[PROP_ACTIVE_ENGINE] = g_param_spec_string ("active-engine",
                                                                                         "active-engine",
                                                                                         "active-engine",
                                                                                         NULL,
                                                                                         G_PARAM_READABLE
                                                                                         | G_PARAM_STATIC_NAME
                                                                                         | G_PARAM_STATIC_NICK
                                                                                         | G_PARAM_STATIC_BLURB);

        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_input_engine_manager_properties);
}

static void
kiosk_input_engine_manager_set_is_loaded (KioskInputEngineManager *self,
                                          gboolean                 is_loaded)
{
        if (self->is_loaded == is_loaded) {
                return;
        }

        if (is_loaded) {
                g_debug ("KioskInputEngineManager: Loaded");
        } else {
                g_debug ("KioskInputEngineManager: Unloaded");
        }

        self->is_loaded = is_loaded;
        g_object_notify (G_OBJECT (self), "is-loaded");
}

gboolean
kiosk_input_engine_manager_is_loaded (KioskInputEngineManager *self)
{
        g_return_val_if_fail (G_IS_OBJECT (self), FALSE);

        return self->is_loaded;
}

static void
kiosk_input_engine_manager_set_active_engine (KioskInputEngineManager *self,
                                              const char              *active_engine)
{
        if (g_strcmp0 (self->active_engine, active_engine) == 0) {
                return;
        }

        if (active_engine == NULL) {
                g_debug ("KioskInputEngineManager: There is now no active input engine");
        } else {
                g_debug ("KioskInputEngineManager: Active input engine is now '%s'", active_engine);
        }

        g_free (self->active_engine);
        self->active_engine = g_strdup (active_engine);

        g_object_notify (G_OBJECT (self), "active-engine");
}

const char *
kiosk_input_engine_manager_get_active_engine (KioskInputEngineManager *self)
{
        return self->active_engine;
}

static void
kiosk_input_engine_manager_set_property (GObject      *object,
                                         guint         property_id,
                                         const GValue *value,
                                         GParamSpec   *param_spec)
{
        KioskInputEngineManager *self = KIOSK_INPUT_ENGINE_MANAGER (object);

        switch (property_id) {
        case PROP_INPUT_SOURCES_MANAGER:
                g_set_weak_pointer (&self->input_sources_manager, g_value_get_object (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_input_engine_manager_get_property (GObject    *object,
                                         guint       property_id,
                                         GValue     *value,
                                         GParamSpec *param_spec)
{
        KioskInputEngineManager *self = KIOSK_INPUT_ENGINE_MANAGER (object);

        switch (property_id) {
        case PROP_IS_LOADED:
                g_value_set_boolean (value, self->is_loaded);
                break;
        case PROP_ACTIVE_ENGINE:
                g_value_set_string (value, self->active_engine);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static gboolean
start_ibus (KioskInputEngineManager *self)
{
        g_autoptr (GSubprocessLauncher) launcher = NULL;
        g_autoptr (GError) error = NULL;
        const char *display;

        g_debug ("KioskInputEngineManager: Starting IBus daemon");
        launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);

        display = g_getenv ("GNOME_SETUP_DISPLAY");

        if (display != NULL) {
                g_subprocess_launcher_setenv (launcher, "DISPLAY", display, TRUE);
        }

        if (meta_is_wayland_compositor ()) {
                g_subprocess_launcher_spawn (launcher, &error, "ibus-daemon", NULL);
        } else {
                g_subprocess_launcher_spawn (launcher, &error, "ibus-daemon", "--xim", NULL);
        }

        if (error != NULL) {
                g_debug ("KioskInputEngineManager: Could not start IBus daemon: %s",
                         error->message);
                return FALSE;
        }

        return TRUE;
}

static void
fetch_available_engines (KioskInputEngineManager *self)
{
        g_autoptr (GList) engines_list = NULL;
        GList *node;

        g_debug ("KioskInputEngineManager: Fetching available IBus engines");

        engines_list = ibus_bus_list_engines (self->bus);

        for (node = engines_list; node != NULL; node = node->next) {
                IBusEngineDesc *engine_description = node->data;
                const char *name = ibus_engine_desc_get_name (engine_description);

                g_hash_table_insert (self->engines,
                                     g_strdup (name),
                                     g_object_ref (engine_description));
        }

        g_debug ("KioskInputEngineManager: Found %d engines.", g_list_length (engines_list));
}

static void
on_active_ibus_engine_changed (KioskInputEngineManager *self,
                               const char              *name)
{
        g_debug ("KioskInputEngineManager: global engine changed");

        kiosk_input_engine_manager_set_active_engine (self, name);
}

static void
on_active_ibus_engine_fetched (IBusBus                 *bus,
                               GAsyncResult            *result,
                               KioskInputEngineManager *self)
{
        g_autoptr (GError) error = NULL;

        ibus_bus_get_global_engine_async_finish (bus, result, &error);

        if (error != NULL) {
                g_debug ("KioskInputEngineManager: Could not fetch engine: %s",
                         error->message);
                kiosk_input_engine_manager_set_active_engine (self, NULL);
        } else {
                g_debug ("KioskInputEngineManager: Done fetching global engine");
        }

        kiosk_input_engine_manager_set_is_loaded (self, TRUE);
}

static void
fetch_active_ibus_engine (KioskInputEngineManager *self)
{
        g_debug ("KioskInputEngineManager: Fetching active IBus global engine...");
        ibus_bus_get_global_engine_async (self->bus,
                                          -1,
                                          self->cancellable,
                                          (GAsyncReadyCallback)
                                          on_active_ibus_engine_fetched,
                                          self);
}

static void
on_ibus_bus_connected (KioskInputEngineManager *self)
{
        g_debug ("KioskInputEngineManager: Connected to IBus");
        fetch_available_engines (self);

        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-input-engine-manager] fetch_active_ibus_engine",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (fetch_active_ibus_engine),
                                                  NULL);
}

static void
on_ibus_bus_disconnected (KioskInputEngineManager *self)
{
        g_debug ("KioskInputEngineManager: Disconnected from IBus");
        g_hash_table_remove_all (self->engines);
        kiosk_input_engine_manager_set_is_loaded (self, FALSE);

        kiosk_input_engine_manager_set_active_engine (self, NULL);
}

static gboolean
kiosk_input_engine_manager_connect_to_ibus (KioskInputEngineManager *self)
{
        gboolean input_engine_started;

        g_debug ("KioskInputEngineManager: Connecting to IBus");

        input_engine_started = start_ibus (self);

        if (!input_engine_started) {
                return FALSE;
        }

        ibus_init ();

        self->engines = g_hash_table_new_full (g_str_hash,
                                               g_str_equal,
                                               (GDestroyNotify) g_free,
                                               (GDestroyNotify) g_object_unref);
        self->bus = ibus_bus_new ();
        g_signal_connect_object (G_OBJECT (self->bus),
                                 "connected",
                                 G_CALLBACK (on_ibus_bus_connected),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->bus),
                                 "disconnected",
                                 G_CALLBACK (on_ibus_bus_disconnected),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->bus),
                                 "global-engine-changed",
                                 G_CALLBACK (on_active_ibus_engine_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
        ibus_bus_set_watch_ibus_signal (self->bus, TRUE);

        return self->bus != NULL;
}

gboolean
kiosk_input_engine_manager_find_layout_for_engine (KioskInputEngineManager *self,
                                                   const char              *engine_name,
                                                   const char             **layout,
                                                   const char             **variant)
{
        IBusEngineDesc *engine_description;

        g_return_val_if_fail (G_IS_OBJECT (self), FALSE);

        g_debug ("KioskInputEngineManager: Fetching input engine '%s'", engine_name);

        engine_description = g_hash_table_lookup (self->engines, engine_name);

        if (engine_description == NULL) {
                g_debug ("KioskInputEngineManager: Could not find input engine");
                return FALSE;
        }

        *layout = ibus_engine_desc_get_layout (engine_description);

        if (g_strcmp0 (*layout, "default") == 0) {
                *layout = DEFAULT_LAYOUT_NAME;
        }

        *variant = ibus_engine_desc_get_layout_variant (engine_description);

        return TRUE;
}

gboolean
kiosk_input_engine_manager_describe_engine (KioskInputEngineManager *self,
                                            const char              *engine_name,
                                            char                   **short_description,
                                            char                   **full_description)
{
        IBusEngineDesc *engine_description;
        const char *locale;

        g_return_val_if_fail (G_IS_OBJECT (self), FALSE);

        g_debug ("KioskInputEngineManager: Fetching input engine '%s'", engine_name);

        engine_description = g_hash_table_lookup (self->engines, engine_name);

        if (engine_description == NULL) {
                g_debug ("KioskInputEngineManager: Could not find input engine");
                return FALSE;
        }

        locale = ibus_engine_desc_get_language (engine_description);
        if (full_description != NULL) {
                const char *language_name, *engine_long_name, *text_domain;

                language_name = ibus_get_language_name (locale);
                text_domain = ibus_engine_desc_get_textdomain (engine_description);
                engine_long_name = ibus_engine_desc_get_longname (engine_description);

                *full_description = g_strdup_printf ("%s (%s)",
                                                     language_name,
                                                     g_dgettext (text_domain, engine_long_name));
        }

        if (short_description != NULL) {
                const char *symbol;

                symbol = ibus_engine_desc_get_symbol (engine_description);

                if (symbol == NULL || symbol[0] == '\0') {
                        char *language_code = NULL;
                        gboolean locale_parsed;

                        locale_parsed = gnome_parse_locale (locale, &language_code, NULL, NULL, NULL);

                        if (!locale_parsed || strlen (language_code) > 3) {
                                *short_description = g_strdup ("⌨");
                        } else {
                                *short_description = language_code;
                        }
                } else {
                        *short_description = g_strdup (symbol);
                }
        }

        return TRUE;
}

gboolean
kiosk_input_engine_manager_activate_engine (KioskInputEngineManager *self,
                                            const char              *engine_name)
{
        IBusEngineDesc *engine_description;

        g_return_val_if_fail (G_IS_OBJECT (self), FALSE);

        if (!self->is_loaded) {
                return engine_name == NULL;
        }

        if (engine_name == NULL) {
                engine_name = DEFAULT_INPUT_ENGINE_NAME;
        }

        g_debug ("KioskInputEngineManager: Activating input engine %s", engine_name);
        engine_description = g_hash_table_lookup (self->engines, engine_name);

        if (engine_description == NULL) {
                g_debug ("KioskInputEngineManager: Could not find input engine");
                return FALSE;
        }

        return ibus_bus_set_global_engine (self->bus, engine_name);
}

static void
tell_session_manager_about_ibus (KioskInputEngineManager *self)
{
        g_autoptr (GDBusConnection) user_bus = NULL;
        g_autoptr (GsmSessionManager) session_manager = NULL;
        g_autoptr (GError) error = NULL;
        g_autoptr (GVariant) reply = NULL;

        g_debug ("KioskInputEngineManager: Telling session manager about IBus");

        user_bus = g_bus_get_sync (G_BUS_TYPE_SESSION,
                                   self->cancellable,
                                   &error);
        if (error != NULL) {
                g_debug ("KioskInputEngineManager: Could not contact user bus: %s",
                         error->message);
                return;
        }

        session_manager = gsm_session_manager_proxy_new_sync (user_bus,
                                                              G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                                              G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                                                              "org.gnome.SessionManager",
                                                              "/org/gnome/SessionManager",
                                                              self->cancellable,
                                                              &error);

        if (error != NULL) {
                g_debug ("KioskInputEngineManager: Could not contact session manager: %s",
                         error->message);
                return;
        }

        gsm_session_manager_call_setenv_sync (session_manager,
                                              "GTK_IM_MODULE",
                                              "ibus",
                                              self->cancellable,
                                              &error);

        if (error != NULL) {
                g_debug ("KioskInputEngineManager: Could not tell session manager about IBus: %s",
                         error->message);
                return;
        }
}

static void
kiosk_input_engine_manager_init (KioskInputEngineManager *self)
{
        gboolean connected_to_ibus;

        g_debug ("KioskInputEngineManager: Initializing");

        self->cancellable = g_cancellable_new ();

        connected_to_ibus = kiosk_input_engine_manager_connect_to_ibus (self);

        if (connected_to_ibus) {
                tell_session_manager_about_ibus (self);
        }
}

static void
kiosk_input_engine_manager_constructed (GObject *object)
{
        G_OBJECT_CLASS (kiosk_input_engine_manager_parent_class)->constructed (object);
}

static void
kiosk_input_engine_manager_dispose (GObject *object)
{
        KioskInputEngineManager *self = KIOSK_INPUT_ENGINE_MANAGER (object);

        g_debug ("KioskInputEngineManager: Disposing");

        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        g_clear_weak_pointer (&self->input_sources_manager);

        G_OBJECT_CLASS (kiosk_input_engine_manager_parent_class)->dispose (object);
}
0707010000001F000081A40000000000000000000000016506F4B700000639000000000000000000000000000000000000003900000000gnome-kiosk-45.0/compositor/kiosk-input-engine-manager.h#pragma once

#include <glib-object.h>

typedef struct _KioskInputSourcesManager KioskInputSourcesManager;

G_BEGIN_DECLS

#define KIOSK_TYPE_INPUT_ENGINE_MANAGER (kiosk_input_engine_manager_get_type ())

G_DECLARE_FINAL_TYPE (KioskInputEngineManager,
                      kiosk_input_engine_manager,
                      KIOSK, INPUT_ENGINE_MANAGER,
                      GObject);

KioskInputEngineManager *kiosk_input_engine_manager_new (KioskInputSourcesManager *manager);
gboolean kiosk_input_engine_manager_is_loaded (KioskInputEngineManager *self);
const char *kiosk_input_engine_manager_get_active_engine (KioskInputEngineManager *self);

gboolean kiosk_input_engine_manager_find_layout_for_engine (KioskInputEngineManager *manager,
                                                            const char              *engine_name,
                                                            const char             **layout,
                                                            const char             **variant);
gboolean kiosk_input_engine_manager_describe_engine (KioskInputEngineManager *manager,
                                                     const char              *engine_name,
                                                     char                   **short_description,
                                                     char                   **full_description);
gboolean kiosk_input_engine_manager_activate_engine (KioskInputEngineManager *manager,
                                                     const char              *engine_name);

G_END_DECLS
07070100000020000081A40000000000000000000000016506F4B700005671000000000000000000000000000000000000003700000000gnome-kiosk-45.0/compositor/kiosk-input-source-group.c#include "config.h"
#include "kiosk-input-source-group.h"

#include <stdlib.h>
#include <string.h>

#include <xkbcommon/xkbcommon.h>

#include <meta/meta-context.h>
#include <meta/meta-backend.h>

#include <meta/display.h>

#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>
#include <libgnome-desktop/gnome-xkb-info.h>

#include "kiosk-gobject-utils.h"
#include "kiosk-input-sources-manager.h"
#include "kiosk-compositor.h"

#define KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS 3

struct _KioskInputSourceGroup
{
        GObject                   parent;

        /* weak references */
        KioskCompositor          *compositor;
        KioskInputSourcesManager *input_sources_manager;
        KioskInputEngineManager  *input_engine_manager;
        KioskXKeyboardManager    *x_keyboard_manager;
        MetaDisplay              *display;
        MetaContext              *context;
        MetaBackend              *backend;

        /* strong references */
        char                     *input_engine_name;
        GPtrArray                *layouts;
        GPtrArray                *variants;
        char                     *options;

        /* state */
        xkb_layout_index_t        layout_index;
};
enum
{
        PROP_COMPOSITOR = 1,
        PROP_INPUT_SOURCES_MANAGER,
        NUMBER_OF_PROPERTIES
};

static GParamSpec *kiosk_input_source_group_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskInputSourceGroup, kiosk_input_source_group, G_TYPE_OBJECT)

static void kiosk_input_source_group_set_property (GObject      *object,
                                                   guint         property_id,
                                                   const GValue *value,
                                                   GParamSpec   *param_spec);
static void kiosk_input_source_group_get_property (GObject    *object,
                                                   guint       property_id,
                                                   GValue     *value,
                                                   GParamSpec *param_spec);

static void kiosk_input_source_group_constructed (GObject *object);
static void kiosk_input_source_group_dispose (GObject *object);

KioskInputSourceGroup *
kiosk_input_source_group_new (KioskCompositor          *compositor,
                              KioskInputSourcesManager *input_sources_manager)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_INPUT_SOURCE_GROUP,
                               "compositor", compositor,
                               "input-sources-manager", input_sources_manager,
                               NULL);

        return KIOSK_INPUT_SOURCE_GROUP (object);
}

static size_t
kiosk_input_source_group_get_number_of_layouts (KioskInputSourceGroup *self)
{
        return self->layouts->len - 1;
}

char *
kiosk_input_source_group_get_selected_layout (KioskInputSourceGroup *self)
{
        size_t number_of_layouts;
        const char *layout, *variant;

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                return NULL;
        }

        layout = g_ptr_array_index (self->layouts, self->layout_index);
        variant = g_ptr_array_index (self->variants, self->layout_index);

        return g_strdup_printf ("%s%s%s",
                                layout,
                                variant != NULL && variant[0] != '\0'? "+" : "",
                                variant != NULL && variant[0] != '\0'? variant : "");
}

char **
kiosk_input_source_group_get_layouts (KioskInputSourceGroup *self)
{
        g_autoptr (GPtrArray) array = NULL;
        size_t i, number_of_layouts;

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        array = g_ptr_array_sized_new (number_of_layouts);

        if (number_of_layouts == 0) {
                goto out;
        }

        for (i = 0; i < number_of_layouts; i++) {
                const char *layout, *variant;

                layout = g_ptr_array_index (self->layouts, i);
                variant = g_ptr_array_index (self->variants, i);

                g_ptr_array_add (array, g_strdup_printf ("%s%s%s", layout,
                                                         variant != NULL && variant[0] != '\0'? "+" : "",
                                                         variant != NULL && variant[0] != '\0'? variant : ""));
        }

out:
        g_ptr_array_add (array, NULL);

        return (char **) g_ptr_array_steal (array, NULL);
}

static void
add_layout (KioskInputSourceGroup *self,
            const char            *layout,
            const char            *variant)
{
        size_t number_of_layouts;

        g_debug ("KioskInputSourceGroup: Adding layout '%s%s%s' to mapping",
                 layout,
                 variant != NULL && variant[0] != '\0'? "+" : "",
                 variant != NULL && variant[0] != '\0'? variant : "");

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        /* Drop terminating NULL */
        g_ptr_array_remove_index (self->layouts, number_of_layouts);
        g_ptr_array_remove_index (self->variants, number_of_layouts);

        g_ptr_array_add (self->layouts, g_strdup (layout));
        g_ptr_array_add (self->variants, g_strdup (variant));

        /* Add back terminating NULL */
        g_ptr_array_add (self->layouts, NULL);
        g_ptr_array_add (self->variants, NULL);
}

gboolean
kiosk_input_source_group_add_layout (KioskInputSourceGroup *self,
                                     const char            *layout,
                                     const char            *variant)
{
        size_t number_of_layouts;

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);
        if (number_of_layouts >= KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS) {
                return FALSE;
        }

        if (self->input_engine_name != NULL) {
                return FALSE;
        }

        add_layout (self, layout, variant);

        return TRUE;
}

static void
kiosk_input_source_group_ensure_layout_for_input_engine (KioskInputSourceGroup *self)
{
        const char *layout = NULL;
        const char *variant = NULL;
        size_t number_of_layouts;
        gboolean layout_found;

        if (self->input_engine_name == NULL) {
                return;
        }

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 1) {
                return;
        }

        g_ptr_array_set_size (self->layouts, 0);
        g_ptr_array_set_size (self->variants, 0);

        g_ptr_array_add (self->layouts, NULL);
        g_ptr_array_add (self->variants, NULL);

        layout_found = kiosk_input_engine_manager_find_layout_for_engine (self->input_engine_manager,
                                                                          self->input_engine_name,
                                                                          &layout,
                                                                          &variant);

        if (layout_found) {
                add_layout (self, layout, variant);
        }
}

gboolean
kiosk_input_source_group_set_input_engine (KioskInputSourceGroup *self,
                                           const char            *engine_name)
{
        g_debug ("KioskInputSourceGroup: Setting input engine to '%s'", engine_name);

        g_free (self->input_engine_name);
        self->input_engine_name = g_strdup (engine_name);

        g_ptr_array_set_size (self->layouts, 0);
        g_ptr_array_set_size (self->variants, 0);

        g_ptr_array_add (self->layouts, NULL);
        g_ptr_array_add (self->variants, NULL);

        return TRUE;
}

const char *
kiosk_input_source_group_get_input_engine (KioskInputSourceGroup *self)
{
        return self->input_engine_name;
}

void
kiosk_input_source_group_set_options (KioskInputSourceGroup *self,
                                      const char            *options)
{
        g_free (self->options);
        self->options = g_strdup (options);
}

const char *
kiosk_input_source_group_get_options (KioskInputSourceGroup *self)
{
        return self->options;
}

gboolean
kiosk_input_source_group_activate (KioskInputSourceGroup *self)
{
        size_t number_of_layouts;
        g_autofree char *layouts = NULL;
        g_autofree char *variants = NULL;
        gboolean keymap_already_set = FALSE;
        gboolean layout_group_already_locked = FALSE;

        g_debug ("KioskInputSourceGroup: Activating input source");

        if (self->input_engine_name != NULL) {
                kiosk_input_source_group_ensure_layout_for_input_engine (self);
        }

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                return FALSE;
        }

        layouts = g_strjoinv (",", (GStrv) self->layouts->pdata);
        variants = g_strjoinv (",", (GStrv) self->variants->pdata);

        if (self->input_engine_name != NULL) {
                gboolean activated;

                activated = kiosk_input_engine_manager_activate_engine (self->input_engine_manager, self->input_engine_name);

                if (!activated) {
                        g_debug ("KioskInputSourceGroup: Could not activate input engine '%s'", self->input_engine_name);
                        return FALSE;
                }
        } else {
                kiosk_input_engine_manager_activate_engine (self->input_engine_manager, NULL);
        }

        if (self->x_keyboard_manager != NULL) {
                keymap_already_set = kiosk_x_keyboard_manager_keymap_is_active (self->x_keyboard_manager, (const char * const *) self->layouts->pdata, (const char * const *) self->variants->pdata, self->options);
                layout_group_already_locked = kiosk_x_keyboard_manager_layout_group_is_locked (self->x_keyboard_manager, self->layout_index);
        }

        if (!keymap_already_set) {
                g_debug ("KioskInputSourceGroup: Setting keyboard mapping to [%s] (%s) [%s]",
                         layouts, variants, self->options);

                meta_backend_set_keymap (self->backend, layouts, variants, self->options);
        }

        if (!layout_group_already_locked) {
                g_debug ("KioskInputSourceGroup: Locking layout to index %d", self->layout_index);
                meta_backend_lock_layout_group (self->backend, self->layout_index);
        }

        if (keymap_already_set && layout_group_already_locked) {
                g_debug ("KioskInputSourceGroup: Input source already active");
        }

        return TRUE;
}

static ssize_t
get_index_of_layout (KioskInputSourceGroup *self,
                     const char            *layout_name)
{
        g_auto (GStrv) layouts;
        size_t i;

        layouts = kiosk_input_source_group_get_layouts (self);
        for (i = 0; layouts[i] != NULL; i++) {
                if (g_strcmp0 (layout_name, layouts[i]) == 0) {
                        return (ssize_t) i;
                }
        }

        return -1;
}

gboolean
kiosk_input_source_group_only_has_layouts (KioskInputSourceGroup *self,
                                           const char * const    *layouts_to_check)
{
        g_auto (GStrv) layouts;

        layouts = kiosk_input_source_group_get_layouts (self);

        return g_strv_equal (layouts_to_check, (const char * const *) layouts);
}

gboolean
kiosk_input_source_group_switch_to_layout (KioskInputSourceGroup *self,
                                           const char            *layout_name)
{
        g_autofree char *active_layout = NULL;
        ssize_t layout_index;

        layout_index = get_index_of_layout (self, layout_name);

        if (layout_index < 0) {
                return FALSE;
        }

        g_debug ("KioskInputSourceGroup: Switching to layout %s", layout_name);

        active_layout = kiosk_input_source_group_get_selected_layout (self);

        self->layout_index = layout_index;

        g_debug ("KioskInputSourceGroup: Switching from layout '%s' to next layout '%s'",
                 active_layout, layout_name);

        meta_backend_lock_layout_group (self->backend, self->layout_index);

        return TRUE;
}

void
kiosk_input_source_group_switch_to_first_layout (KioskInputSourceGroup *self)
{
        size_t number_of_layouts;
        g_autofree char *layout_to_activate = NULL;

        g_debug ("KioskInputSourceGroup: Switching mapping to first layout");

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                g_debug ("KioskInputSourceGroup: Mapping has no layouts");
                return;
        }

        self->layout_index = 0;
        layout_to_activate = kiosk_input_source_group_get_selected_layout (self);

        g_debug ("KioskInputSourceGroup: First layout is '%s'", layout_to_activate);
        meta_backend_lock_layout_group (self->backend, self->layout_index);
}

void
kiosk_input_source_group_switch_to_last_layout (KioskInputSourceGroup *self)
{
        size_t number_of_layouts;
        g_autofree char *layout_to_activate = NULL;

        g_debug ("KioskInputSourceGroup: Switching mapping to last layout");

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                g_debug ("KioskInputSourceGroup: Mapping has no layouts");
                return;
        }

        self->layout_index = number_of_layouts - 1;
        layout_to_activate = kiosk_input_source_group_get_selected_layout (self);

        g_debug ("KioskInputSourceGroup: Last layout is '%s'", layout_to_activate);
        meta_backend_lock_layout_group (self->backend, self->layout_index);
}

gboolean
kiosk_input_source_group_switch_to_next_layout (KioskInputSourceGroup *self)
{
        size_t number_of_layouts, last_layout_index;
        g_autofree char *active_layout = NULL;
        g_autofree char *layout_to_activate = NULL;

        g_debug ("KioskInputSourceGroup: Switching mapping forward one layout");

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                g_debug ("KioskInputSourceGroup: Mapping has no layouts");
                return FALSE;
        }

        last_layout_index = number_of_layouts - 1;

        if (self->layout_index + 1 > last_layout_index) {
                g_debug ("KioskInputSourceGroup: Mapping is at last layout");
                return FALSE;
        }

        active_layout = kiosk_input_source_group_get_selected_layout (self);

        self->layout_index++;

        layout_to_activate = kiosk_input_source_group_get_selected_layout (self);

        g_debug ("KioskInputSourceGroup: Switching from layout '%s' to next layout '%s'",
                 active_layout, layout_to_activate);

        meta_backend_lock_layout_group (self->backend, self->layout_index);

        return TRUE;
}

gboolean
kiosk_input_source_group_switch_to_previous_layout (KioskInputSourceGroup *self)
{
        size_t number_of_layouts;
        g_autofree char *active_layout = NULL;
        g_autofree char *layout_to_activate = NULL;

        g_debug ("KioskInputSourceGroup: Switching mapping backward one layout");

        number_of_layouts = kiosk_input_source_group_get_number_of_layouts (self);

        if (number_of_layouts == 0) {
                g_debug ("KioskInputSourceGroup: Mapping has no layouts");
                return FALSE;
        }

        if (self->layout_index == 0) {
                g_debug ("KioskInputSourceGroup: Mapping is at first layout");
                return FALSE;
        }

        active_layout = kiosk_input_source_group_get_selected_layout (self);

        self->layout_index--;

        layout_to_activate = kiosk_input_source_group_get_selected_layout (self);

        g_debug ("KioskInputSourceGroup: Switching from layout '%s' to previous layout '%s'",
                 active_layout, layout_to_activate);

        meta_backend_lock_layout_group (self->backend, self->layout_index);

        return TRUE;
}

static void
kiosk_input_source_group_class_init (KioskInputSourceGroupClass *input_sources_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (input_sources_class);

        object_class->constructed = kiosk_input_source_group_constructed;
        object_class->set_property = kiosk_input_source_group_set_property;
        object_class->get_property = kiosk_input_source_group_get_property;
        object_class->dispose = kiosk_input_source_group_dispose;

        kiosk_input_source_group_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                                    "compositor",
                                                                                    "compositor",
                                                                                    KIOSK_TYPE_COMPOSITOR,
                                                                                    G_PARAM_CONSTRUCT_ONLY
                                                                                    | G_PARAM_WRITABLE
                                                                                    | G_PARAM_STATIC_NAME
                                                                                    | G_PARAM_STATIC_NICK
                                                                                    | G_PARAM_STATIC_BLURB);
        kiosk_input_source_group_properties[PROP_INPUT_SOURCES_MANAGER] = g_param_spec_object ("input-sources-manager",
                                                                                               "input-sources-manager",
                                                                                               "input-sources-manager",
                                                                                               KIOSK_TYPE_INPUT_SOURCES_MANAGER,
                                                                                               G_PARAM_CONSTRUCT_ONLY
                                                                                               | G_PARAM_WRITABLE
                                                                                               | G_PARAM_STATIC_NAME
                                                                                               | G_PARAM_STATIC_NICK
                                                                                               | G_PARAM_STATIC_BLURB);

        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_input_source_group_properties);
}

static void
kiosk_input_source_group_set_property (GObject      *object,
                                       guint         property_id,
                                       const GValue *value,
                                       GParamSpec   *param_spec)
{
        KioskInputSourceGroup *self = KIOSK_INPUT_SOURCE_GROUP (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;
        case PROP_INPUT_SOURCES_MANAGER:
                g_set_weak_pointer (&self->input_sources_manager, g_value_get_object (value));
                break;

        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_input_source_group_get_property (GObject    *object,
                                       guint       property_id,
                                       GValue     *value,
                                       GParamSpec *param_spec)
{
        switch (property_id) {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_input_source_group_init (KioskInputSourceGroup *self)
{
        g_debug ("KioskInputSourceGroup: Initializing");

        self->layouts = g_ptr_array_new_full (KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS + 1, g_free);
        self->variants = g_ptr_array_new_full (KIOSK_INPUT_SOURCE_GROUP_MAX_LAYOUTS + 1, g_free);

        g_ptr_array_add (self->layouts, NULL);
        g_ptr_array_add (self->variants, NULL);
}

static void
kiosk_input_source_group_constructed (GObject *object)
{
        KioskInputSourceGroup *self = KIOSK_INPUT_SOURCE_GROUP (object);

        G_OBJECT_CLASS (kiosk_input_source_group_parent_class)->constructed (object);

        g_set_weak_pointer (&self->input_engine_manager, kiosk_input_sources_manager_get_input_engine_manager (self->input_sources_manager));
        g_set_weak_pointer (&self->x_keyboard_manager, kiosk_input_sources_manager_get_x_keyboard_manager (self->input_sources_manager));
        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
        g_set_weak_pointer (&self->backend, meta_context_get_backend (self->context));
}

static void
kiosk_input_source_group_dispose (GObject *object)
{
        KioskInputSourceGroup *self = KIOSK_INPUT_SOURCE_GROUP (object);

        g_debug ("KioskInputSourceGroup: Disposing");

        g_clear_pointer (&self->options, g_free);

        g_clear_pointer (&self->variants, g_ptr_array_unref);
        g_clear_pointer (&self->layouts, g_ptr_array_unref);

        g_clear_weak_pointer (&self->backend);
        g_clear_weak_pointer (&self->context);
        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->x_keyboard_manager);
        g_clear_weak_pointer (&self->input_engine_manager);
        g_clear_weak_pointer (&self->input_sources_manager);

        G_OBJECT_CLASS (kiosk_input_source_group_parent_class)->dispose (object);
}
07070100000021000081A40000000000000000000000016506F4B70000093D000000000000000000000000000000000000003700000000gnome-kiosk-45.0/compositor/kiosk-input-source-group.h#pragma once

#include <glib-object.h>

typedef struct _KioskCompositor KioskCompositor;

typedef struct _KioskInputSourcesManager KioskInputSourcesManager;

G_BEGIN_DECLS

#define KIOSK_TYPE_INPUT_SOURCE_GROUP (kiosk_input_source_group_get_type ())

G_DECLARE_FINAL_TYPE (KioskInputSourceGroup,
                      kiosk_input_source_group,
                      KIOSK, INPUT_SOURCE_GROUP,
                      GObject);

KioskInputSourceGroup *kiosk_input_source_group_new (KioskCompositor          *compositor,
                                                     KioskInputSourcesManager *manager);
gboolean kiosk_input_source_group_add_layout (KioskInputSourceGroup *input_sources,
                                              const char            *layout,
                                              const char            *variant);
char *kiosk_input_source_group_get_selected_layout (KioskInputSourceGroup *input_sources);
char **kiosk_input_source_group_get_layouts (KioskInputSourceGroup *input_sources);

gboolean kiosk_input_source_group_set_input_engine (KioskInputSourceGroup *input_sources,
                                                    const char            *engine_name);
const char *kiosk_input_source_group_get_input_engine (KioskInputSourceGroup *input_sources);

void kiosk_input_source_group_set_options (KioskInputSourceGroup *input_sources,
                                           const char            *options);
const char *kiosk_input_source_group_get_options (KioskInputSourceGroup *self);

gboolean kiosk_input_source_group_activate (KioskInputSourceGroup *input_sources);

gboolean kiosk_input_source_group_only_has_layouts (KioskInputSourceGroup *self,
                                                    const char * const    *layouts_to_check);
gboolean kiosk_input_source_group_switch_to_layout (KioskInputSourceGroup *input_sources,
                                                    const char            *layout_name);
void kiosk_input_source_group_switch_to_first_layout (KioskInputSourceGroup *input_sources);
void kiosk_input_source_group_switch_to_last_layout (KioskInputSourceGroup *input_sources);
gboolean kiosk_input_source_group_switch_to_next_layout (KioskInputSourceGroup *input_sources);
gboolean kiosk_input_source_group_switch_to_previous_layout (KioskInputSourceGroup *input_sources);
G_END_DECLS
07070100000022000081A40000000000000000000000016506F4B70001066F000000000000000000000000000000000000003A00000000gnome-kiosk-45.0/compositor/kiosk-input-sources-manager.c#include "config.h"
#include "kiosk-input-sources-manager.h"

#include <stdlib.h>
#include <string.h>

#include <xkbcommon/xkbcommon.h>
#include <meta/display.h>
#include <meta/keybindings.h>
#include <meta/util.h>

#include <meta/meta-backend.h>
#include <meta/meta-plugin.h>

#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-languages.h>
#include <libgnome-desktop/gnome-xkb-info.h>

#include "org.freedesktop.locale1.h"
#include "kiosk-compositor.h"
#include "kiosk-dbus-utils.h"
#include "kiosk-gobject-utils.h"
#include "kiosk-input-engine-manager.h"
#include "kiosk-input-source-group.h"
#include "kiosk-x-keyboard-manager.h"

#define SD_LOCALE1_BUS_NAME "org.freedesktop.locale1"
#define SD_LOCALE1_OBJECT_PATH "/org/freedesktop/locale1"

#define KIOSK_INPUT_SOURCES_SCHEMA "org.gnome.desktop.input-sources"
#define KIOSK_INPUT_SOURCES_SETTING "sources"
#define KIOSK_INPUT_OPTIONS_SETTING "xkb-options"

#define KIOSK_INPUT_SOURCE_OBJECTS_PATH_PREFIX "/org/gnome/Kiosk/InputSources"
#define KIOSK_KEYBINDINGS_SCHEMA "org.gnome.desktop.wm.keybindings"
#define KIOSK_SWITCH_INPUT_SOURCES_KEYBINDING "switch-input-source"
#define KIOSK_SWITCH_INPUT_SOURCES_BACKWARD_KEYBINDING "switch-input-source-backward"

#define KIOSK_DBUS_INPUT_SOURCES_MANGER_INPUT_SOURCE_INTERFACE "org.gnome.Kiosk.InputSources.InputSource"

struct _KioskInputSourcesManager
{
        GObject                       parent;

        /* weak references */
        KioskCompositor              *compositor;
        MetaDisplay                  *display;

        KioskDBusInputSourcesManager *dbus_service;
        GDBusObjectManagerServer     *dbus_object_manager;

        /* strong references */
        GCancellable                 *cancellable;
        KioskInputEngineManager      *input_engine_manager;
        KioskXKeyboardManager        *x_keyboard_manager;
        SdLocale1                    *locale_proxy;
        GnomeXkbInfo                 *xkb_info;
        GSettings                    *input_sources_settings;
        GSettings                    *key_binding_settings;
        GPtrArray                    *input_source_groups;

        /* state */
        ssize_t                       input_source_groups_index;

        /* flags */
        guint32                       overriding_configuration : 1;
};

enum
{
        PROP_COMPOSITOR = 1,
        NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_input_sources_manager_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskInputSourcesManager, kiosk_input_sources_manager, G_TYPE_OBJECT)

static void kiosk_input_sources_manager_set_property (GObject      *object,
                                                      guint         property_id,
                                                      const GValue *value,
                                                      GParamSpec   *param_spec);
static void kiosk_input_sources_manager_get_property (GObject    *object,
                                                      guint       property_id,
                                                      GValue     *value,
                                                      GParamSpec *param_spec);

static void kiosk_input_sources_manager_constructed (GObject *object);
static void kiosk_input_sources_manager_dispose (GObject *object);
static void kiosk_input_sources_manager_switch_to_next_input_source (KioskInputSourcesManager *self);
static void kiosk_input_sources_manager_switch_to_previous_input_source (KioskInputSourcesManager *self);
static void sync_dbus_service (KioskInputSourcesManager *self);

KioskInputSourcesManager *
kiosk_input_sources_manager_new (KioskCompositor *compositor)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_INPUT_SOURCES_MANAGER,
                               "compositor", compositor,
                               NULL);

        return KIOSK_INPUT_SOURCES_MANAGER (object);
}

static void
kiosk_input_sources_manager_class_init (KioskInputSourcesManagerClass *input_sources_manager_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (input_sources_manager_class);

        object_class->constructed = kiosk_input_sources_manager_constructed;
        object_class->set_property = kiosk_input_sources_manager_set_property;
        object_class->get_property = kiosk_input_sources_manager_get_property;
        object_class->dispose = kiosk_input_sources_manager_dispose;

        kiosk_input_sources_manager_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                                       "compositor",
                                                                                       "compositor",
                                                                                       KIOSK_TYPE_COMPOSITOR,
                                                                                       G_PARAM_CONSTRUCT_ONLY
                                                                                       | G_PARAM_WRITABLE
                                                                                       | G_PARAM_STATIC_NAME
                                                                                       | G_PARAM_STATIC_NICK
                                                                                       | G_PARAM_STATIC_BLURB);
        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_input_sources_manager_properties);
}

static KioskInputSourceGroup *
kiosk_input_sources_manager_get_selected_input_source_group (KioskInputSourcesManager *self)
{
        if (self->input_source_groups->len == 0) {
                return NULL;
        }

        return g_ptr_array_index (self->input_source_groups, self->input_source_groups_index);
}

static gboolean
activate_first_available_input_source_group (KioskInputSourcesManager *self)
{
        size_t i;

        for (i = 0; i < self->input_source_groups->len; i++) {
                KioskInputSourceGroup *input_source_group = g_ptr_array_index (self->input_source_groups, i);
                gboolean input_source_group_active;

                input_source_group_active = kiosk_input_source_group_activate (input_source_group);

                if (input_source_group_active) {
                        self->input_source_groups_index = i;
                        sync_dbus_service (self);
                        return TRUE;
                }
        }

        return FALSE;
}

static gboolean
activate_input_source_group_if_it_has_engine (KioskInputSourcesManager *self,
                                              KioskInputSourceGroup    *input_source_group,
                                              const char               *name)
{
        const char *input_engine_name = NULL;
        gboolean input_source_group_active;

        input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);

        if (g_strcmp0 (input_engine_name, name) != 0) {
                return FALSE;
        }

        input_source_group_active = kiosk_input_source_group_activate (input_source_group);

        if (input_source_group_active) {
                sync_dbus_service (self);
        }

        return input_source_group_active;
}

static gboolean
activate_input_source_group_with_engine (KioskInputSourcesManager *self,
                                         const char               *name)
{
        KioskInputSourceGroup *input_source_group;
        gboolean input_source_group_active = FALSE;
        size_t i;

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group != NULL) {
                input_source_group_active = activate_input_source_group_if_it_has_engine (self, input_source_group, name);
        }

        if (input_source_group_active) {
                return TRUE;
        }

        for (i = 0; i < self->input_source_groups->len; i++) {
                input_source_group = g_ptr_array_index (self->input_source_groups, i);

                input_source_group_active = activate_input_source_group_if_it_has_engine (self, input_source_group, name);

                if (input_source_group_active) {
                        self->input_source_groups_index = i;
                        return TRUE;
                }
        }

        return FALSE;
}

static gboolean
activate_input_source_group_if_it_has_layout (KioskInputSourcesManager *self,
                                              KioskInputSourceGroup    *input_source_group,
                                              const char               *name)
{
        const char *selected_layout = NULL;
        gboolean layout_selected, input_source_group_active;

        selected_layout = kiosk_input_source_group_get_selected_layout (input_source_group);

        if (g_strcmp0 (selected_layout, name) == 0) {
                layout_selected = TRUE;
        } else {
                layout_selected = kiosk_input_source_group_switch_to_layout (input_source_group, name);
        }

        if (layout_selected) {
                input_source_group_active = kiosk_input_source_group_activate (input_source_group);
        }

        if (input_source_group_active) {
                sync_dbus_service (self);
        }

        return input_source_group_active;
}

static gboolean
activate_input_source_group_with_layout (KioskInputSourcesManager *self,
                                         const char               *name)
{
        KioskInputSourceGroup *input_source_group;
        gboolean input_source_group_active = FALSE;
        size_t i;

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group != NULL) {
                input_source_group_active = activate_input_source_group_if_it_has_layout (self, input_source_group, name);
        }

        if (input_source_group_active) {
                return TRUE;
        }

        for (i = 0; i < self->input_source_groups->len; i++) {
                input_source_group = g_ptr_array_index (self->input_source_groups, i);

                input_source_group_active = activate_input_source_group_if_it_has_layout (self, input_source_group, name);

                if (input_source_group_active) {
                        self->input_source_groups_index = i;
                        return TRUE;
                }
        }

        return FALSE;
}

static gboolean
activate_best_available_input_source_group (KioskInputSourcesManager *self,
                                            const char               *input_engine,
                                            const char               *selected_layout)
{
        gboolean input_source_group_active = FALSE;

        if (input_engine != NULL) {
                input_source_group_active = activate_input_source_group_with_engine (self, input_engine);
        } else if (selected_layout != NULL) {
                input_source_group_active = activate_input_source_group_with_layout (self, selected_layout);
        }

        if (!input_source_group_active) {
                input_source_group_active = activate_first_available_input_source_group (self);
        }

        return input_source_group_active;
}

static char *
get_dbus_object_path_name_for_input_source (KioskInputSourcesManager *self,
                                            const char               *type,
                                            const char               *name)
{
        g_autofree char *escaped_name = NULL;
        g_autofree char *base_name = NULL;
        char *object_path;

        escaped_name = kiosk_dbus_utils_escape_object_path (name, strlen (name));
        base_name = g_strdup_printf ("%s_%s", type, escaped_name);

        object_path = g_build_path ("/", KIOSK_INPUT_SOURCE_OBJECTS_PATH_PREFIX, base_name, NULL);

        return object_path;
}

static void
sync_selected_input_source_to_dbus_service (KioskInputSourcesManager *self)
{
        KioskInputSourceGroup *input_source_group;
        const char *backend_type;
        const char *backend_id;
        const char *input_engine_name;
        g_autofree char *selected_layout = NULL;
        g_autofree char *object_path_name = NULL;

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group == NULL) {
                return;
        }

        input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);

        if (input_engine_name != NULL) {
                backend_type = "ibus";
                backend_id = input_engine_name;
        } else {
                selected_layout = kiosk_input_source_group_get_selected_layout (input_source_group);

                if (selected_layout == NULL) {
                        return;
                }

                backend_type = "xkb";
                backend_id = selected_layout;
        }

        object_path_name = get_dbus_object_path_name_for_input_source (self, backend_type, backend_id);

        g_debug ("KioskInputSourceGroup: Setting SelectedInputSource D-Bus property to %s", object_path_name);

        kiosk_dbus_input_sources_manager_set_selected_input_source (self->dbus_service, object_path_name);
}

static void
export_input_source_object_to_dbus_service (KioskInputSourcesManager *self,
                                            const char               *object_path_name,
                                            const char               *backend_type,
                                            const char               *backend_id,
                                            const char               *short_name,
                                            const char               *full_name)
{
        g_autoptr (GDBusInterface) dbus_input_source = NULL;
        g_autoptr (GDBusObject) object_path = NULL;

        dbus_input_source = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (self->dbus_object_manager),
                                                                 object_path_name,
                                                                 KIOSK_DBUS_INPUT_SOURCES_MANGER_INPUT_SOURCE_INTERFACE);

        if (dbus_input_source == NULL) {
                dbus_input_source = G_DBUS_INTERFACE (kiosk_dbus_input_source_skeleton_new ());
        }

        kiosk_dbus_input_source_set_backend_type (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source), backend_type);
        kiosk_dbus_input_source_set_full_name (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source), full_name);
        kiosk_dbus_input_source_set_short_name (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source), short_name);
        kiosk_dbus_input_source_set_backend_id (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source), backend_id);

        object_path = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->dbus_object_manager),
                                                        object_path_name);

        if (object_path == NULL) {
                object_path = G_DBUS_OBJECT (kiosk_dbus_object_skeleton_new (object_path_name));
                g_dbus_object_manager_server_export (self->dbus_object_manager, G_DBUS_OBJECT_SKELETON (object_path));
        }

        kiosk_dbus_object_skeleton_set_input_source (KIOSK_DBUS_OBJECT_SKELETON (object_path), KIOSK_DBUS_INPUT_SOURCE (dbus_input_source));
}

static GList *
prune_object_path_from_list (KioskInputSourcesManager *self,
                             const char               *name,
                             GList                    *list)
{
        GList *node;

        for (node = list; node != NULL; node = node->next) {
                GDBusObject *dbus_object = node->data;
                const char *candidate_name = g_dbus_object_get_object_path (dbus_object);

                if (g_strcmp0 (candidate_name, name) == 0) {
                        list = g_list_remove_link (list, node);
                        g_object_unref (dbus_object);
                        return list;
                }
        }

        return list;
}

static void
unexport_input_sources_from_dbus_service (KioskInputSourcesManager *self,
                                          GList                    *list)
{
        GList *node;

        for (node = list; node != NULL; node = node->next) {
                GDBusObject *dbus_object = node->data;
                g_autoptr (GDBusInterface) dbus_input_source = NULL;
                const char *name = g_dbus_object_get_object_path (dbus_object);

                dbus_input_source = g_dbus_object_get_interface (dbus_object, KIOSK_DBUS_INPUT_SOURCES_MANGER_INPUT_SOURCE_INTERFACE);
                if (dbus_input_source == NULL) {
                        continue;
                }

                g_dbus_object_manager_server_unexport (G_DBUS_OBJECT_MANAGER_SERVER (self->dbus_object_manager),
                                                       name);
        }
}

static void
sync_all_input_sources_to_dbus_service (KioskInputSourcesManager *self)
{
        GList *stale_dbus_objects;

        g_autoptr (GPtrArray) sorted_input_sources = NULL;
        g_autofree char *input_sources_string;
        size_t i;

        stale_dbus_objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->dbus_object_manager));

        sorted_input_sources = g_ptr_array_new_full (self->input_source_groups->len * 3, g_free);
        for (i = 0; i < self->input_source_groups->len; i++) {
                KioskInputSourceGroup *input_source_group = g_ptr_array_index (self->input_source_groups, i);
                const char *input_engine_name;
                const char *backend_type;
                const char *backend_id;
                g_auto (GStrv) layouts = NULL;
                size_t i;

                input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);

                if (input_engine_name != NULL) {
                        char *object_path_name = NULL;
                        g_autofree char *full_name = NULL;
                        g_autofree char *short_name = NULL;

                        backend_type = "ibus";
                        backend_id = input_engine_name;

                        kiosk_input_engine_manager_describe_engine (self->input_engine_manager, input_engine_name, &short_name, &full_name);

                        object_path_name = get_dbus_object_path_name_for_input_source (self, backend_type, backend_id);
                        stale_dbus_objects = prune_object_path_from_list (self,
                                                                          object_path_name,
                                                                          stale_dbus_objects);
                        export_input_source_object_to_dbus_service (self, object_path_name, backend_type, backend_id, short_name, full_name);
                        g_ptr_array_add (sorted_input_sources, object_path_name);
                        continue;
                }

                layouts = kiosk_input_source_group_get_layouts (input_source_group);

                backend_type = "xkb";
                for (i = 0; layouts[i] != NULL; i++) {
                        char *object_path_name = NULL;
                        const char *short_name = NULL;
                        const char *full_name = NULL;
                        gboolean layout_info_found;

                        backend_id = layouts[i];

                        layout_info_found = gnome_xkb_info_get_layout_info (self->xkb_info,
                                                                            backend_id,
                                                                            &full_name,
                                                                            &short_name,
                                                                            NULL /* xkb layout */,
                                                                            NULL /* xkb variant */);

                        if (!layout_info_found) {
                                continue;
                        }

                        object_path_name = get_dbus_object_path_name_for_input_source (self, backend_type, backend_id);
                        stale_dbus_objects = prune_object_path_from_list (self,
                                                                          object_path_name,
                                                                          stale_dbus_objects);

                        export_input_source_object_to_dbus_service (self, object_path_name, backend_type, backend_id, short_name, full_name);
                        g_ptr_array_add (sorted_input_sources, object_path_name);
                }
        }
        g_ptr_array_add (sorted_input_sources, NULL);
        unexport_input_sources_from_dbus_service (self, stale_dbus_objects);
        g_list_free_full (stale_dbus_objects, g_object_unref);

        input_sources_string = g_strjoinv ("','", (GStrv) sorted_input_sources->pdata);
        g_debug ("KioskInputSourcesManager: InputSources D-Bus property set to ['%s']", input_sources_string);
        kiosk_dbus_input_sources_manager_set_input_sources (self->dbus_service, (const char * const *) sorted_input_sources->pdata);
}

static void
sync_dbus_service_now (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Synchronizing D-Bus service with internal state");

        sync_all_input_sources_to_dbus_service (self);
        sync_selected_input_source_to_dbus_service (self);
}

static void
sync_dbus_service (KioskInputSourcesManager *self)
{
        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-input-sources-manager] on_deferred_dbus_service_sync",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (sync_dbus_service_now),
                                                  NULL);
}

static gboolean
kiosk_input_sources_manager_set_input_sources (KioskInputSourcesManager *self,
                                               GVariant                 *input_sources,
                                               const char * const       *options)
{
        KioskInputSourceGroup *old_input_source_group;
        g_autofree char *old_input_engine = NULL;
        g_autofree char *old_selected_layout = NULL;

        g_autoptr (GVariantIter) iter = NULL;
        g_autofree char *options_string = NULL;
        const char *backend_type = NULL, *backend_id = NULL;
        gboolean input_source_group_active;

        old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (old_input_source_group != NULL) {
                old_input_engine = g_strdup (kiosk_input_source_group_get_input_engine (old_input_source_group));
                old_selected_layout = kiosk_input_source_group_get_selected_layout (old_input_source_group);
        }

        kiosk_input_sources_manager_clear_input_sources (self);

        options_string = g_strjoinv (",", (GStrv) options);

        g_variant_get (input_sources, "a(ss)", &iter);
        while (g_variant_iter_loop (iter, "(ss)", &backend_type, &backend_id)) {
                if (g_strcmp0 (backend_type, "xkb") == 0) {
                        g_debug ("KioskInputSourcesManager:         %s", backend_id);
                        kiosk_input_sources_manager_add_layout (self, backend_id, options_string);
                } else if (g_strcmp0 (backend_type, "ibus") == 0) {
                        g_debug ("KioskInputSourcesManager:         %s", backend_id);
                        kiosk_input_sources_manager_add_input_engine (self, backend_id, options_string);
                } else {
                        g_debug ("KioskInputSourcesManager: Unknown input source type '%s' for source '%s'", backend_type, backend_id);
                }
        }

        input_source_group_active = activate_best_available_input_source_group (self, old_input_engine, old_selected_layout);

        sync_dbus_service (self);

        return input_source_group_active;
}

static void
kiosk_input_sources_manager_set_property (GObject      *object,
                                          guint         property_id,
                                          const GValue *value,
                                          GParamSpec   *param_spec)
{
        KioskInputSourcesManager *self = KIOSK_INPUT_SOURCES_MANAGER (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;

        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_input_sources_manager_get_property (GObject    *object,
                                          guint       property_id,
                                          GValue     *value,
                                          GParamSpec *param_spec)
{
        switch (property_id) {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static gboolean
on_dbus_service_handle_set_input_sources (KioskInputSourcesManager *self,
                                          GDBusMethodInvocation    *invocation,
                                          GVariant                 *input_sources,
                                          const char * const       *options)
{
        g_autoptr (GVariantIter) iter = NULL;
        g_autofree char *input_sources_string = NULL;
        g_autofree char *options_string = NULL;

        input_sources_string = g_variant_print (input_sources, FALSE);
        options_string = g_strjoinv (",", (GStrv) options);

        g_debug ("KioskService: Handling SetInputSources(%s, [%s]) call",
                 input_sources_string, options_string);

        kiosk_input_sources_manager_set_input_sources (self, input_sources, options);

        kiosk_dbus_input_sources_manager_complete_set_input_sources (self->dbus_service, invocation);

        return TRUE;
}

static gboolean
on_dbus_service_handle_set_input_sources_from_locales (KioskInputSourcesManager *self,
                                                       GDBusMethodInvocation    *invocation,
                                                       const char * const       *locales,
                                                       const char * const       *options)
{
        g_autofree char *locales_string = NULL;
        g_autofree char *options_string = NULL;

        locales_string = g_strjoinv (",", (GStrv) locales);
        options_string = g_strjoinv (",", (GStrv) options);

        g_debug ("KioskService: Handling SetInputSourcesFromLocales([%s], [%s]) call",
                 locales_string, options_string);

        kiosk_input_sources_manager_set_input_sources_from_locales (self, locales, options_string);
        kiosk_dbus_input_sources_manager_complete_set_input_sources_from_locales (self->dbus_service, invocation);

        return TRUE;
}

static gboolean
on_dbus_service_handle_set_input_sources_from_session_configuration (KioskInputSourcesManager *self,
                                                                     GDBusMethodInvocation    *invocation)
{
        g_debug ("KioskService: Handling SetInputSourcesFromSessionConfiguration() call");

        kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);
        kiosk_dbus_input_sources_manager_complete_set_input_sources_from_session_configuration (self->dbus_service, invocation);

        return TRUE;
}

static gboolean
on_dbus_service_handle_select_input_source (KioskInputSourcesManager *self,
                                            GDBusMethodInvocation    *invocation,
                                            const char               *object_path)
{
        g_autoptr (GDBusInterface) dbus_input_source = NULL;

        g_debug ("KioskService: Handling SelectInputSource('%s') call", object_path);

        dbus_input_source = g_dbus_object_manager_get_interface (G_DBUS_OBJECT_MANAGER (self->dbus_object_manager),
                                                                 object_path,
                                                                 KIOSK_DBUS_INPUT_SOURCES_MANGER_INPUT_SOURCE_INTERFACE);
        if (dbus_input_source != NULL) {
                const char *source_type = NULL;
                const char *source_name = NULL;
                const char *input_engine = NULL;
                const char *layout_name = NULL;

                source_type = kiosk_dbus_input_source_get_backend_type (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source));
                source_name = kiosk_dbus_input_source_get_backend_id (KIOSK_DBUS_INPUT_SOURCE (dbus_input_source));

                if (g_strcmp0 (source_type, "ibus") == 0) {
                        input_engine = source_name;
                } else if (g_strcmp0 (source_type, "xkb") == 0) {
                        layout_name = source_name;
                }

                activate_best_available_input_source_group (self, input_engine, layout_name);
        }

        kiosk_dbus_input_sources_manager_complete_select_input_source (self->dbus_service, invocation);

        return TRUE;
}

static gboolean
on_dbus_service_handle_select_next_input_source (KioskInputSourcesManager *self,
                                                 GDBusMethodInvocation    *invocation)
{
        g_debug ("KioskService: Handling SelectNextInputSource() call");

        kiosk_input_sources_manager_switch_to_next_input_source (self);
        kiosk_dbus_input_sources_manager_complete_select_next_input_source (self->dbus_service, invocation);

        return TRUE;
}

static gboolean
on_dbus_service_handle_select_previous_input_source (KioskInputSourcesManager *self,
                                                     GDBusMethodInvocation    *invocation)
{
        g_debug ("KioskService: Handling SelectPreviousInputSource() call");

        kiosk_input_sources_manager_switch_to_previous_input_source (self);
        kiosk_dbus_input_sources_manager_complete_select_previous_input_source (self->dbus_service, invocation);

        return TRUE;
}

KioskInputEngineManager *
kiosk_input_sources_manager_get_input_engine_manager (KioskInputSourcesManager *self)
{
        return self->input_engine_manager;
}

KioskXKeyboardManager *
kiosk_input_sources_manager_get_x_keyboard_manager (KioskInputSourcesManager *self)
{
        return self->x_keyboard_manager;
}

void
kiosk_input_sources_manager_clear_input_sources (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Clearing selected keyboard mappings");

        g_ptr_array_set_size (self->input_source_groups, 0);
        self->input_source_groups_index = 0;
}

static void
kiosk_input_sources_manager_add_input_source_group (KioskInputSourcesManager *self,
                                                    KioskInputSourceGroup    *input_source_group)
{
        g_ptr_array_add (self->input_source_groups, g_object_ref (input_source_group));
}

static KioskInputSourceGroup *
kiosk_input_sources_manager_add_new_input_source_group (KioskInputSourcesManager *self,
                                                        const char               *options)
{
        g_autoptr (KioskInputSourceGroup) input_source_group = NULL;

        g_debug ("KioskInputSourcesManager: Adding new, empty keyboard mapping with options '%s'",
                 options);

        input_source_group = kiosk_input_source_group_new (self->compositor, self);
        kiosk_input_source_group_set_options (input_source_group, options);

        kiosk_input_sources_manager_add_input_source_group (self, input_source_group);

        return input_source_group;
}

static KioskInputSourceGroup *
kiosk_input_sources_manager_get_newest_input_source_group (KioskInputSourcesManager *self)
{
        if (self->input_source_groups->len == 0) {
                return NULL;
        }

        return g_ptr_array_index (self->input_source_groups, self->input_source_groups->len - 1);
}

void
kiosk_input_sources_manager_add_layout (KioskInputSourcesManager *self,
                                        const char               *id,
                                        const char               *options)
{
        KioskInputSourceGroup *input_source_group = NULL;
        const char *xkb_layout = NULL;
        const char *xkb_variant = NULL;
        gboolean layout_info_found;
        gboolean mapping_full;

        g_debug ("KioskInputSourcesManager: Adding layout '%s' to keyboard mapping", id);

        layout_info_found = gnome_xkb_info_get_layout_info (self->xkb_info,
                                                            id,
                                                            NULL /* display name */,
                                                            NULL /* short name */,
                                                            &xkb_layout,
                                                            &xkb_variant);

        if (!layout_info_found) {
                g_debug ("KioskInputSourcesManager: Layout not found");
                return;
        }

        input_source_group = kiosk_input_sources_manager_get_newest_input_source_group (self);

        if (input_source_group == NULL) {
                g_debug ("KioskInputSourcesManager: No keyboard mappings found, creating one");

                input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);
        }

        mapping_full = !kiosk_input_source_group_add_layout (input_source_group, xkb_layout, xkb_variant);

        if (mapping_full) {
                g_debug ("KioskInputSourcesManager: Keyboard mapping full, starting another one");

                input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);

                kiosk_input_source_group_add_layout (input_source_group, xkb_layout, xkb_variant);
        }
}

void
kiosk_input_sources_manager_add_input_engine (KioskInputSourcesManager *self,
                                              const char               *engine_name,
                                              const char               *options)
{
        KioskInputSourceGroup *input_source_group = NULL;

        g_debug ("KioskInputSourcesManager: Adding input engine '%s'", engine_name);

        input_source_group = kiosk_input_sources_manager_add_new_input_source_group (self, options);

        kiosk_input_source_group_set_input_engine (input_source_group, engine_name);
        kiosk_input_source_group_set_options (input_source_group, options);
}


gboolean
kiosk_input_sources_manager_set_input_sources_from_system_configuration (KioskInputSourcesManager *self)
{
        KioskInputSourceGroup *old_input_source_group;
        g_autofree char *old_input_engine = NULL;
        g_autofree char *old_selected_layout = NULL;
        g_autofree char *localed_name_owner = NULL;

        const char *layouts_string = NULL;

        g_auto (GStrv) layouts = NULL;
        size_t number_of_layouts = 0;

        const char *variants_string = NULL;

        g_auto (GStrv) variants = NULL;
        size_t number_of_variants = 0;

        const char *options = NULL;
        size_t i, j;

        gboolean input_source_group_active;

        g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE);

        if (self->locale_proxy == NULL) {
                return FALSE;
        }

        localed_name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (self->locale_proxy));

        if (localed_name_owner == NULL) {
                return FALSE;
        }

        g_debug ("KioskInputSourcesManager: Setting keymap from system configuration");

        layouts_string = sd_locale1_get_x11_layout (self->locale_proxy);
        g_debug ("KioskInputSourcesManager: System layout is '%s'", layouts_string);

        layouts = g_strsplit (layouts_string, ",", -1);
        number_of_layouts = g_strv_length (layouts);

        options = sd_locale1_get_x11_options (self->locale_proxy);
        g_debug ("KioskInputSourcesManager: System layout options are '%s'", options);

        variants_string = sd_locale1_get_x11_variant (self->locale_proxy);
        g_debug ("KioskInputSourcesManager: System layout variant is '%s'", variants_string);
        variants = g_strsplit (variants_string, ",", -1);
        number_of_variants = g_strv_length (variants);

        if (number_of_layouts < number_of_variants) {
                g_debug ("KioskInputSourcesManager: There is a layout variant mismatch");
                return FALSE;
        }

        old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (old_input_source_group != NULL) {
                old_input_engine = g_strdup (kiosk_input_source_group_get_input_engine (old_input_source_group));
                old_selected_layout = kiosk_input_source_group_get_selected_layout (old_input_source_group);
        }

        kiosk_input_sources_manager_clear_input_sources (self);

        for (i = 0, j = 0; layouts[i] != NULL; i++) {
                char *id = NULL;
                const char *layout = layouts[i];
                const char *variant = "";

                if (variants[j] != NULL) {
                        variant = variants[j++];
                }

                if (variant[0] == '\0') {
                        id = g_strdup (layout);
                } else {
                        id = g_strdup_printf ("%s+%s", layout, variant);
                }

                kiosk_input_sources_manager_add_layout (self, id, options);
        }

        input_source_group_active = activate_best_available_input_source_group (self, old_input_engine, old_selected_layout);

        if (!input_source_group_active) {
                const char * const *locales;

                locales = sd_locale1_get_locale (self->locale_proxy);
                input_source_group_active = kiosk_input_sources_manager_set_input_sources_from_locales (self, locales, options);
        }

        sync_dbus_service (self);
        self->overriding_configuration = FALSE;

        if (!input_source_group_active) {
                g_debug ("KioskInputSourcesManager: System has no valid configured input sources");
                return FALSE;
        }

        return TRUE;
}

static void
on_session_input_configuration_changed (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Session input sources configuration changed");

        if (self->overriding_configuration) {
                g_debug ("KioskInputSourcesManager: Ignoring change, because keymap is overriden");
                return;
        }

        kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);
}

static void
on_session_input_sources_setting_changed (KioskInputSourcesManager *self)
{
        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-input-sources-manager] on_session_input_configuration_changed",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (on_session_input_configuration_changed),
                                                  NULL);
}

gboolean
kiosk_input_sources_manager_set_input_sources_from_session_configuration (KioskInputSourcesManager *self)
{
        g_autoptr (GVariant) input_sources = NULL;
        g_auto (GStrv) options = NULL;
        gboolean input_sources_active;

        g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE);

        g_debug ("KioskInputSourcesManager: Setting input sources from session configuration");

        self->overriding_configuration = FALSE;

        if (self->input_sources_settings == NULL) {
                self->input_sources_settings = g_settings_new (KIOSK_INPUT_SOURCES_SCHEMA);

                g_signal_connect_object (G_OBJECT (self->input_sources_settings),
                                         "changed::" KIOSK_INPUT_SOURCES_SETTING,
                                         G_CALLBACK (on_session_input_sources_setting_changed),
                                         self,
                                         G_CONNECT_SWAPPED);
                g_signal_connect_object (G_OBJECT (self->input_sources_settings),
                                         "changed::" KIOSK_INPUT_OPTIONS_SETTING,
                                         G_CALLBACK (on_session_input_sources_setting_changed),
                                         self,
                                         G_CONNECT_SWAPPED);
        }


        options = g_settings_get_strv (self->input_sources_settings, KIOSK_INPUT_OPTIONS_SETTING);

        input_sources = g_settings_get_value (self->input_sources_settings,
                                              KIOSK_INPUT_SOURCES_SETTING);

        input_sources_active = kiosk_input_sources_manager_set_input_sources (self, input_sources, (const char * const *) options);

        if (!input_sources_active) {
                g_debug ("KioskInputSourcesManager: Session has no valid configured input sources");
                return kiosk_input_sources_manager_set_input_sources_from_system_configuration (self);
        }

        return TRUE;
}

gboolean
kiosk_input_sources_manager_set_input_sources_from_locales (KioskInputSourcesManager *self,
                                                            const char * const       *locales,
                                                            const char               *options)
{
        KioskInputSourceGroup *old_input_source_group;
        g_autofree char *old_selected_layout = NULL;
        g_autofree char *old_input_engine = NULL;
        g_autofree char *locales_string = NULL;
        gboolean input_source_group_active;

        g_return_val_if_fail (KIOSK_IS_INPUT_SOURCES_MANAGER (self), FALSE);
        g_return_val_if_fail (locales != NULL, FALSE);

        locales_string = g_strjoinv (",", (GStrv) locales);

        g_debug ("KioskInputSourcesManager: Setting keymap from locales '%s'",
                 locales_string);

        self->overriding_configuration = TRUE;

        old_input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (old_input_source_group != NULL) {
                old_selected_layout = kiosk_input_source_group_get_selected_layout (old_input_source_group);
                old_input_engine = g_strdup (kiosk_input_source_group_get_input_engine (old_input_source_group));
        }

        kiosk_input_sources_manager_clear_input_sources (self);

        for (int i = 0; locales[i] != NULL; i++) {
                const char *locale = locales[i];
                const char *backend_type, *backend_id;
                gboolean input_source_found;

                input_source_found = gnome_get_input_source_from_locale (locale,
                                                                         &backend_type,
                                                                         &backend_id);

                if (!input_source_found) {
                        g_debug ("KioskInputSourcesManager: Could not find keymap details from locale '%s'",
                                 locale);
                        continue;
                }

                if (g_strcmp0 (backend_type, "xkb") == 0) {
                        g_debug ("KioskInputSourcesManager: Found XKB input source '%s' for locale '%s'",
                                 backend_id, locale);

                        kiosk_input_sources_manager_add_layout (self, backend_id, options);
                } else if (g_strcmp0 (backend_type, "ibus") == 0) {
                        g_debug ("KioskInputSourcesManager: Found IBus input source '%s' for locale '%s'",
                                 backend_id, locale);

                        kiosk_input_sources_manager_add_input_engine (self, backend_id, options);
                } else {
                        g_debug ("KioskInputSourcesManager: Unknown input source type '%s' for source '%s'", backend_type, backend_id);
                }
        }

        input_source_group_active = activate_first_available_input_source_group (self);

        sync_dbus_service (self);

        if (!input_source_group_active) {
                g_debug ("KioskInputSourcesManager: Locales haves no valid associated keyboard mappings");
                return FALSE;
        }

        return TRUE;
}

static void
on_system_configuration_changed (KioskInputSourcesManager *self)
{
        g_autofree char *localed_owner = NULL;

        localed_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (self->locale_proxy));

        if (localed_owner == NULL) {
                g_debug ("KioskInputSourcesManager: System locale daemon exited");
                return;
        }

        g_debug ("KioskInputSourcesManager: System locale configuration changed");

        if (self->overriding_configuration) {
                g_debug ("KioskInputSourcesManager: Ignoring change, because keymap is overriden");
                return;
        }

        kiosk_input_sources_manager_set_input_sources_from_system_configuration (self);
}

static void
on_localed_property_notify (KioskInputSourcesManager *self)
{
        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-input-sources-manager] on_system_configuration_changed",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (on_system_configuration_changed),
                                                  NULL);
}

static gboolean
kiosk_input_sources_manager_connect_to_localed (KioskInputSourcesManager *self)
{
        g_autoptr (GDBusConnection) system_bus = NULL;
        g_autoptr (GError) error = NULL;

        g_debug ("KioskInputSourcesManager: Connecting to localed");

        system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
                                     self->cancellable,
                                     &error);

        self->locale_proxy = sd_locale1_proxy_new_sync (system_bus,
                                                        G_DBUS_PROXY_FLAGS_NONE,
                                                        SD_LOCALE1_BUS_NAME,
                                                        SD_LOCALE1_OBJECT_PATH,
                                                        self->cancellable,
                                                        &error);

        if (error != NULL) {
                g_debug ("KioskInputSourcesManager: Could not connect to localed: %s",
                         error->message);
                return FALSE;
        } else {
                g_debug ("KioskInputSourcesManager: Connected to localed");

                g_signal_connect_object (G_OBJECT (self->locale_proxy),
                                         "notify",
                                         G_CALLBACK (on_localed_property_notify),
                                         self,
                                         G_CONNECT_SWAPPED);
        }

        return TRUE;
}

static void
kiosk_input_sources_manager_activate_input_sources (KioskInputSourcesManager *self)
{
        KioskInputSourceGroup *input_source_group;
        gboolean input_source_group_active;

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group == NULL) {
                g_debug ("KioskInputSourcesManager: No available keyboard mappings");
                return;
        }

        input_source_group_active = kiosk_input_source_group_activate (input_source_group);

        if (input_source_group_active) {
                sync_dbus_service (self);
        }
}

static void
kiosk_input_sources_manager_cycle_input_sources_forward (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Cycling input sources forward");

        self->input_source_groups_index++;

        if (self->input_source_groups_index >= self->input_source_groups->len) {
                KioskInputSourceGroup *input_source_group;

                self->input_source_groups_index -= self->input_source_groups->len;
                input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);
                kiosk_input_source_group_switch_to_first_layout (input_source_group);
        }

        kiosk_input_sources_manager_activate_input_sources (self);
}

static void
kiosk_input_sources_manager_cycle_input_sources_backward (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Cycling input sources backward");

        self->input_source_groups_index--;

        if (self->input_source_groups_index < 0) {
                KioskInputSourceGroup *input_source_group;

                self->input_source_groups_index += self->input_source_groups->len;
                input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);
                kiosk_input_source_group_switch_to_last_layout (input_source_group);
        }

        kiosk_input_sources_manager_activate_input_sources (self);
}

static void
kiosk_input_sources_manager_switch_to_next_input_source (KioskInputSourcesManager *self)
{
        KioskInputSourceGroup *input_source_group = NULL;
        gboolean had_next_layout;

        g_debug ("KioskInputSourcesManager: Switching to next input sources");

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group == NULL) {
                g_debug ("KioskInputSourcesManager: No input sources available");
                return;
        }

        had_next_layout = kiosk_input_source_group_switch_to_next_layout (input_source_group);

        if (!had_next_layout) {
                kiosk_input_sources_manager_cycle_input_sources_forward (self);
        }

        sync_dbus_service (self);
}

static void
kiosk_input_sources_manager_switch_to_previous_input_source (KioskInputSourcesManager *self)
{
        KioskInputSourceGroup *input_source_group = NULL;
        gboolean had_previous_layout;

        g_debug ("KioskInputSourcesManager: Switching to next input sources");

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group == NULL) {
                g_debug ("KioskInputSourcesManager: No input sources available");
                return;
        }

        had_previous_layout = kiosk_input_source_group_switch_to_previous_layout (input_source_group);

        if (!had_previous_layout) {
                kiosk_input_sources_manager_cycle_input_sources_backward (self);
        }

        sync_dbus_service (self);
}

static void
on_switch_input_sources (MetaDisplay              *display,
                         MetaWindow               *window,
                         ClutterKeyEvent          *event,
                         MetaKeyBinding           *binding,
                         KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Keybinding pressed to change input source");

        if (meta_key_binding_is_reversed (binding)) {
                kiosk_input_sources_manager_switch_to_previous_input_source (self);
        } else {
                kiosk_input_sources_manager_switch_to_next_input_source (self);
        }
}

static void
kiosk_input_sources_manager_add_key_bindings (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Adding key bindings for layout switching");

        self->key_binding_settings = g_settings_new (KIOSK_KEYBINDINGS_SCHEMA);
        meta_display_add_keybinding (self->display,
                                     KIOSK_SWITCH_INPUT_SOURCES_KEYBINDING,
                                     self->key_binding_settings,
                                     META_KEY_BINDING_NONE,
                                     (MetaKeyHandlerFunc)
                                     on_switch_input_sources,
                                     self,
                                     NULL);

        meta_display_add_keybinding (self->display,
                                     KIOSK_SWITCH_INPUT_SOURCES_BACKWARD_KEYBINDING,
                                     self->key_binding_settings,
                                     META_KEY_BINDING_IS_REVERSED,
                                     (MetaKeyHandlerFunc)
                                     on_switch_input_sources,
                                     self,
                                     NULL);
}

static void
kiosk_input_sources_manager_remove_key_bindings (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Removing key bindings for layout switching");
        meta_display_remove_keybinding (self->display, KIOSK_SWITCH_INPUT_SOURCES_BACKWARD_KEYBINDING);
        meta_display_remove_keybinding (self->display, KIOSK_SWITCH_INPUT_SOURCES_KEYBINDING);

        g_clear_object (&self->key_binding_settings);
}

static void
kiosk_input_sources_manager_maybe_activate_higher_priority_input_engine (KioskInputSourcesManager *self)
{
        size_t i;

        /* It's possible the user has an input engine configured to be used, but it wasn't ready
         * before. If so, now that it's ready, we should activate it.
         */
        for (i = 0; i < self->input_source_groups_index; i++) {
                KioskInputSourceGroup *input_source_group = g_ptr_array_index (self->input_source_groups, i);
                const char *input_engine_name = NULL;
                gboolean input_source_group_active;

                input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);

                if (input_engine_name == NULL) {
                        break;
                }

                input_source_group_active = kiosk_input_source_group_activate (input_source_group);

                if (input_source_group_active) {
                        sync_dbus_service (self);
                        return;
                }
        }

        g_debug ("KioskInputSourcesManager: No higher priority input engines found, reactivating existing input source");
        kiosk_input_sources_manager_activate_input_sources (self);
}

static void
on_input_engine_manager_is_loaded_changed (KioskInputSourcesManager *self)
{
        gboolean input_engine_manager_is_loaded;

        input_engine_manager_is_loaded = kiosk_input_engine_manager_is_loaded (self->input_engine_manager);

        if (!input_engine_manager_is_loaded) {
                g_debug ("KioskInputSourcesManager: Input engine manager unloaded, activating first available input source");

                activate_first_available_input_source_group (self);
                return;
        }

        g_debug ("KioskInputSourcesManager: Input engine manager loaded, reevaluating available input sources");
        kiosk_input_sources_manager_maybe_activate_higher_priority_input_engine (self);
}

static void
on_input_engine_manager_active_engine_changed (KioskInputSourcesManager *self)
{
        gboolean is_loaded;
        const char *active_input_engine;

        is_loaded = kiosk_input_engine_manager_is_loaded (self->input_engine_manager);

        if (!is_loaded) {
                g_debug ("KioskInputSourcesManager: Input engine changed while input engine manager unloaded. Ignoring...");
                return;
        }

        active_input_engine = kiosk_input_engine_manager_get_active_engine (self->input_engine_manager);

        if (active_input_engine == NULL) {
                g_debug ("KioskInputSourcesManager: Input engine deactivated, activating first available input source");
                activate_first_available_input_source_group (self);
                return;
        }

        activate_input_source_group_with_engine (self, active_input_engine);
}

static void
kiosk_input_sources_manager_start_input_engine_manager (KioskInputSourcesManager *self)
{
        self->input_engine_manager = kiosk_input_engine_manager_new (self);

        g_signal_connect_object (G_OBJECT (self->input_engine_manager),
                                 "notify::is-loaded",
                                 G_CALLBACK (on_input_engine_manager_is_loaded_changed),
                                 self,
                                 G_CONNECT_SWAPPED);

        g_signal_connect_object (G_OBJECT (self->input_engine_manager),
                                 "notify::active-engine",
                                 G_CALLBACK (on_input_engine_manager_active_engine_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
process_x_keyboard_manager_selected_layout_change (KioskInputSourcesManager *self)
{
        const char *selected_layout;

        selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);

        if (selected_layout == NULL) {
                return;
        }

        g_debug ("KioskInputSourcesManager: X server changed active layout to %s", selected_layout);

        activate_input_source_group_with_layout (self, selected_layout);

        sync_dbus_service (self);
}

static void
on_x_keyboard_manager_selected_layout_changed (KioskInputSourcesManager *self)
{
        /* We defer processing the layout change for a bit, because often in practice there is more than
         * one layout change at the same time, and only the last one is the desired one
         */
        kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                  "[kiosk-input-sources-manager] process_x_keyboard_manager_selected_layout_change",
                                                  self->cancellable,
                                                  KIOSK_OBJECT_CALLBACK (process_x_keyboard_manager_selected_layout_change),
                                                  NULL);
}

static gboolean
layouts_match_selected_input_source_group (KioskInputSourcesManager *self,
                                           const char * const       *layouts,
                                           const char               *options)
{
        KioskInputSourceGroup *input_source_group;

        g_auto (GStrv) current_layouts = NULL;
        const char *input_source_group_options;
        const char *input_engine_name;

        input_source_group = kiosk_input_sources_manager_get_selected_input_source_group (self);

        if (input_source_group == NULL) {
                return FALSE;
        }

        input_engine_name = kiosk_input_source_group_get_input_engine (input_source_group);

        if (input_engine_name != NULL) {
                return FALSE;
        }

        current_layouts = kiosk_input_source_group_get_layouts (input_source_group);

        if (!g_strv_equal ((const char * const *) current_layouts, layouts)) {
                return FALSE;
        }

        input_source_group_options = kiosk_input_source_group_get_options (input_source_group);

        if (g_strcmp0 (input_source_group_options, options) != 0) {
                return FALSE;
        }

        return TRUE;
}

static void
on_x_keyboard_manager_layouts_changed (KioskInputSourcesManager *self)
{
        const char * const *new_layouts;
        const char *selected_layout;
        const char *options;
        gboolean layouts_match;
        size_t i;

        new_layouts = kiosk_x_keyboard_manager_get_layouts (self->x_keyboard_manager);
        options = kiosk_x_keyboard_manager_get_options (self->x_keyboard_manager);
        layouts_match = layouts_match_selected_input_source_group (self, new_layouts, options);

        if (layouts_match) {
                return;
        }

        g_debug ("KioskInputSorcesManager: X server keyboard layouts changed");

        self->overriding_configuration = TRUE;
        kiosk_input_sources_manager_clear_input_sources (self);

        for (i = 0; new_layouts[i] != NULL; i++) {
                kiosk_input_sources_manager_add_layout (self, new_layouts[i], options);
        }

        selected_layout = kiosk_x_keyboard_manager_get_selected_layout (self->x_keyboard_manager);

        if (selected_layout != NULL) {
                activate_best_available_input_source_group (self, NULL, selected_layout);
        }
}

static void
kiosk_input_source_manager_start_x_keyboard_manager (KioskInputSourcesManager *self)
{
        g_debug ("KioskInputSourcesManager: Starting X Keyboard Manager");
        self->x_keyboard_manager = kiosk_x_keyboard_manager_new (self->compositor);

        g_signal_connect_object (G_OBJECT (self->x_keyboard_manager),
                                 "notify::selected-layout",
                                 G_CALLBACK (on_x_keyboard_manager_selected_layout_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->x_keyboard_manager),
                                 "notify::layouts",
                                 G_CALLBACK (on_x_keyboard_manager_layouts_changed),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
kiosk_input_sources_manager_handle_dbus_service (KioskInputSourcesManager *self)
{
        KioskService *service;

        service = kiosk_compositor_get_service (self->compositor);

        g_set_weak_pointer (&self->dbus_service, KIOSK_DBUS_INPUT_SOURCES_MANAGER (kiosk_service_get_input_sources_manager_skeleton (service)));
        g_set_weak_pointer (&self->dbus_object_manager, kiosk_service_get_input_sources_object_manager (service));

        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-set-input-sources",
                                 G_CALLBACK (on_dbus_service_handle_set_input_sources),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-set-input-sources-from-locales",
                                 G_CALLBACK (on_dbus_service_handle_set_input_sources_from_locales),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-set-input-sources-from-session-configuration",
                                 G_CALLBACK (on_dbus_service_handle_set_input_sources_from_session_configuration),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-select-input-source",
                                 G_CALLBACK (on_dbus_service_handle_select_input_source),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-select-next-input-source",
                                 G_CALLBACK (on_dbus_service_handle_select_next_input_source),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->dbus_service),
                                 "handle-select-previous-input-source",
                                 G_CALLBACK (on_dbus_service_handle_select_previous_input_source),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
kiosk_input_sources_manager_constructed (GObject *object)
{
        KioskInputSourcesManager *self = KIOSK_INPUT_SOURCES_MANAGER (object);

        g_debug ("KioskInputSourcesManager: Initializing");

        G_OBJECT_CLASS (kiosk_input_sources_manager_parent_class)->constructed (object);

        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));

        self->cancellable = g_cancellable_new ();

        self->xkb_info = gnome_xkb_info_new ();
        self->input_source_groups = g_ptr_array_new_full (1, g_object_unref);

        kiosk_input_sources_manager_handle_dbus_service (self);

        kiosk_input_sources_manager_start_input_engine_manager (self);

        kiosk_input_sources_manager_connect_to_localed (self);

        kiosk_input_sources_manager_add_key_bindings (self);

        kiosk_input_sources_manager_set_input_sources_from_session_configuration (self);

        /* We start the X keyboard manager after we've already loaded and locked in
         * GSettings etc, so the session settings take precedence over xorg.conf
         */
        if (!meta_is_wayland_compositor ()) {
                g_debug ("KioskInputSourcesManager: Will start X keyboard manager shortly");
                kiosk_gobject_utils_queue_defer_callback (G_OBJECT (self),
                                                          "[kiosk-input-sources-manager] kiosk_input_source_manager_start_x_keyboard_manager",
                                                          self->cancellable,
                                                          KIOSK_OBJECT_CALLBACK (kiosk_input_source_manager_start_x_keyboard_manager),
                                                          NULL);
        } else {
                g_debug ("KioskInputSourcesManager: Won't start X keyboard manager on wayland");
        }
}

static void
kiosk_input_sources_manager_init (KioskInputSourcesManager *self)
{
}

static void
kiosk_input_sources_manager_dispose (GObject *object)
{
        KioskInputSourcesManager *self = KIOSK_INPUT_SOURCES_MANAGER (object);

        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        kiosk_input_sources_manager_clear_input_sources (self);

        g_clear_object (&self->input_engine_manager);
        g_clear_object (&self->x_keyboard_manager);

        g_clear_object (&self->xkb_info);

        g_clear_object (&self->locale_proxy);

        kiosk_input_sources_manager_remove_key_bindings (self);
        g_clear_weak_pointer (&self->dbus_service);
        g_clear_weak_pointer (&self->dbus_object_manager);
        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->compositor);

        G_OBJECT_CLASS (kiosk_input_sources_manager_parent_class)->dispose (object);
}
07070100000023000081A40000000000000000000000016506F4B700000729000000000000000000000000000000000000003A00000000gnome-kiosk-45.0/compositor/kiosk-input-sources-manager.h#pragma once

#include <glib-object.h>

#include "kiosk-input-source-group.h"
#include "kiosk-input-engine-manager.h"
#include "kiosk-x-keyboard-manager.h"

typedef struct _KioskCompositor KioskCompositor;

G_BEGIN_DECLS

#define KIOSK_TYPE_INPUT_SOURCES_MANAGER (kiosk_input_sources_manager_get_type ())

G_DECLARE_FINAL_TYPE (KioskInputSourcesManager,
                      kiosk_input_sources_manager,
                      KIOSK, INPUT_SOURCES_MANAGER,
                      GObject);

KioskInputSourcesManager *kiosk_input_sources_manager_new (KioskCompositor *compositor);
KioskInputEngineManager *kiosk_input_sources_manager_get_input_engine_manager (KioskInputSourcesManager *manager);
KioskXKeyboardManager *kiosk_input_sources_manager_get_x_keyboard_manager (KioskInputSourcesManager *manager);

void kiosk_input_sources_manager_clear_input_sources (KioskInputSourcesManager *self);
gboolean kiosk_input_sources_manager_set_input_sources_from_locales (KioskInputSourcesManager *self,
                                                                     const char * const       *locales,
                                                                     const char               *options);
gboolean kiosk_input_sources_manager_set_input_sources_from_session_configuration (KioskInputSourcesManager *manager);

void kiosk_input_sources_manager_add_layout (KioskInputSourcesManager *self,
                                             const char               *layout,
                                             const char               *options);
void kiosk_input_sources_manager_add_input_engine (KioskInputSourcesManager *self,
                                                   const char               *engine_name,
                                                   const char               *options);

G_END_DECLS
07070100000024000081A40000000000000000000000016506F4B700002615000000000000000000000000000000000000002C00000000gnome-kiosk-45.0/compositor/kiosk-service.c#include "config.h"
#include "kiosk-service.h"

#include <stdlib.h>
#include <string.h>
#include <meta/display.h>
#include <meta/util.h>

#include "kiosk-compositor.h"

#define KIOSK_SERVICE_BUS_NAME "org.gnome.Kiosk"
#define KIOSK_SERVICE_OBJECT_PATH "/org/gnome/Kiosk"

#define KIOSK_SERVICE_INPUT_SOURCES_OBJECTS_PATH_PREFIX KIOSK_SERVICE_OBJECT_PATH "/InputSources"
#define KIOSK_SERVICE_INPUT_SOURCES_MANAGER_OBJECT_PATH KIOSK_SERVICE_INPUT_SOURCES_OBJECTS_PATH_PREFIX "/Manager"

struct _KioskService
{
        GObject                               parent;

        /* weak references */
        KioskCompositor                      *compositor;

        /* strong references */
        KioskDBusServiceSkeleton             *service_skeleton;

        KioskDBusInputSourcesManagerSkeleton *input_sources_manager_skeleton;
        GDBusObjectManagerServer             *input_sources_object_manager;

        /* handles */
        guint                                 bus_id;
};

enum
{
        PROP_COMPOSITOR = 1,
        NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_service_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskService, kiosk_service, G_TYPE_OBJECT);

static void kiosk_service_set_property (GObject      *object,
                                        guint         property_id,
                                        const GValue *value,
                                        GParamSpec   *param_spec);
static void kiosk_service_get_property (GObject    *object,
                                        guint       property_id,
                                        GValue     *value,
                                        GParamSpec *param_spec);

static void kiosk_service_constructed (GObject *object);
static void kiosk_service_dispose (GObject *object);

KioskService *
kiosk_service_new (KioskCompositor *compositor)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_SERVICE,
                               "compositor", compositor,
                               NULL);

        return KIOSK_SERVICE (object);
}

static void
kiosk_service_class_init (KioskServiceClass *service_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (service_class);

        object_class->constructed = kiosk_service_constructed;
        object_class->set_property = kiosk_service_set_property;
        object_class->get_property = kiosk_service_get_property;
        object_class->dispose = kiosk_service_dispose;

        kiosk_service_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                         "compositor",
                                                                         "compositor",
                                                                         KIOSK_TYPE_COMPOSITOR,
                                                                         G_PARAM_CONSTRUCT_ONLY
                                                                         | G_PARAM_WRITABLE
                                                                         | G_PARAM_STATIC_NAME
                                                                         | G_PARAM_STATIC_NICK
                                                                         | G_PARAM_STATIC_BLURB);
        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_service_properties);
}

static void
kiosk_service_set_property (GObject      *object,
                            guint         property_id,
                            const GValue *value,
                            GParamSpec   *param_spec)
{
        KioskService *self = KIOSK_SERVICE (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;

        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_service_get_property (GObject    *object,
                            guint       property_id,
                            GValue     *value,
                            GParamSpec *param_spec)
{
        switch (property_id) {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_service_constructed (GObject *object)
{
        G_OBJECT_CLASS (kiosk_service_parent_class)->constructed (object);
}

static void
kiosk_service_init (KioskService *self)
{
        g_debug ("KioskService: Initializing");
        self->service_skeleton = KIOSK_DBUS_SERVICE_SKELETON (kiosk_dbus_service_skeleton_new ());

        self->input_sources_manager_skeleton = KIOSK_DBUS_INPUT_SOURCES_MANAGER_SKELETON (kiosk_dbus_input_sources_manager_skeleton_new ());
        self->input_sources_object_manager = g_dbus_object_manager_server_new (KIOSK_SERVICE_INPUT_SOURCES_OBJECTS_PATH_PREFIX);
}

static void
export_service (KioskService    *self,
                GDBusConnection *connection)
{
        g_autoptr (GError) error = NULL;

        g_debug ("KioskService: Exporting service over user bus");

        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->service_skeleton),
                                          connection, KIOSK_SERVICE_OBJECT_PATH, &error);

        if (error != NULL) {
                g_debug ("KioskService: Could not export service over user bus: %s", error->message);
                g_clear_error (&error);
        }
}

static void
export_input_sources_manager (KioskService    *self,
                              GDBusConnection *connection)
{
        g_autoptr (GDBusObjectSkeleton) object = NULL;

        g_debug ("KioskService: Exporting input sources manager over bus");

        object = g_dbus_object_skeleton_new (KIOSK_SERVICE_INPUT_SOURCES_MANAGER_OBJECT_PATH);
        g_dbus_object_skeleton_add_interface (object, G_DBUS_INTERFACE_SKELETON (self->input_sources_manager_skeleton));
        g_dbus_object_manager_server_export (G_DBUS_OBJECT_MANAGER_SERVER (self->input_sources_object_manager), G_DBUS_OBJECT_SKELETON (object));

        g_dbus_object_manager_server_set_connection (G_DBUS_OBJECT_MANAGER_SERVER (self->input_sources_object_manager), connection);
}

static void
on_user_bus_acquired (GDBusConnection *connection,
                      const char      *unique_name,
                      KioskService    *self)
{
        g_debug ("KioskService: Connected to user bus");

        export_service (self, connection);
        export_input_sources_manager (self, connection);
}

static void
on_bus_name_acquired (GDBusConnection *connection,
                      const char      *name,
                      KioskService    *self)
{
        if (g_strcmp0 (name, KIOSK_SERVICE_BUS_NAME) != 0) {
                return;
        }

        g_debug ("KioskService: Acquired name %s", name);
}

static void
on_bus_name_lost (GDBusConnection *connection,
                  const char      *name,
                  KioskService    *self)
{
        if (g_strcmp0 (name, KIOSK_SERVICE_BUS_NAME) != 0) {
                return;
        }

        g_debug ("KioskService: Lost name %s", name);

        /* If the name got stolen from us, assume we're getting
         * replaced and terminate immediately.
         *
         * If we've just lost our name as part of getting stopped, that's non-fatal.
         */
        if (self->bus_id != 0) {
                g_debug ("KioskService: Terminating");
                raise (SIGTERM);
        }
}

gboolean
kiosk_service_start (KioskService *self,
                     GError      **error)
{
        g_return_val_if_fail (KIOSK_IS_SERVICE (self), FALSE);

        g_debug ("KioskService: Starting");

        self->bus_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                                       KIOSK_SERVICE_BUS_NAME,
                                       G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
                                       (GBusAcquiredCallback) on_user_bus_acquired,
                                       (GBusNameAcquiredCallback) on_bus_name_acquired,
                                       (GBusNameVanishedCallback) on_bus_name_lost,
                                       self,
                                       NULL);

        return TRUE;
}

void
kiosk_service_stop (KioskService *self)
{
        g_return_if_fail (KIOSK_IS_SERVICE (self));

        g_debug ("KioskService: Stopping");

        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->service_skeleton));
        g_dbus_object_manager_server_unexport (G_DBUS_OBJECT_MANAGER_SERVER (self->input_sources_manager_skeleton),
                                               KIOSK_SERVICE_INPUT_SOURCES_MANAGER_OBJECT_PATH);

        g_clear_handle_id (&self->bus_id, g_bus_unown_name);
}

KioskDBusInputSourcesManagerSkeleton *
kiosk_service_get_input_sources_manager_skeleton (KioskService *self)
{
        return self->input_sources_manager_skeleton;
}

GDBusObjectManagerServer *
kiosk_service_get_input_sources_object_manager (KioskService *self)
{
        return self->input_sources_object_manager;
}

static void
kiosk_service_dispose (GObject *object)
{
        KioskService *self = KIOSK_SERVICE (object);

        g_debug ("KioskService: Disposing");

        kiosk_service_stop (self);

        g_clear_object (&self->input_sources_manager_skeleton);
        g_clear_object (&self->input_sources_object_manager);
        g_clear_weak_pointer (&self->compositor);

        G_OBJECT_CLASS (kiosk_service_parent_class)->dispose (object);
}
07070100000025000081A40000000000000000000000016506F4B7000002FC000000000000000000000000000000000000002C00000000gnome-kiosk-45.0/compositor/kiosk-service.h#pragma once

#include <glib-object.h>
#include "org.gnome.Kiosk.h"

typedef struct _KioskCompositor KioskCompositor;

G_BEGIN_DECLS

#define KIOSK_TYPE_SERVICE (kiosk_service_get_type ())

G_DECLARE_FINAL_TYPE (KioskService,
                      kiosk_service,
                      KIOSK, SERVICE,
                      GObject);

KioskService *kiosk_service_new (KioskCompositor *compositor);

gboolean kiosk_service_start (KioskService *self,
                              GError      **error);
void kiosk_service_stop (KioskService *self);

KioskDBusInputSourcesManagerSkeleton *kiosk_service_get_input_sources_manager_skeleton (KioskService *self);
GDBusObjectManagerServer *kiosk_service_get_input_sources_object_manager (KioskService *self);

G_END_DECLS
07070100000026000081A40000000000000000000000016506F4B7000050D3000000000000000000000000000000000000003200000000gnome-kiosk-45.0/compositor/kiosk-shell-service.c#include "config.h"
#include "kiosk-shell-service.h"

#include <stdlib.h>
#include <string.h>
#include <meta/display.h>
#include <meta/util.h>

#include "kiosk-compositor.h"

#define KIOSK_SHELL_SERVICE_BUS_NAME "org.gnome.Shell"
#define KIOSK_SHELL_SERVICE_OBJECT_PATH "/org/gnome/Shell"

struct _KioskShellService
{
        KioskShellDBusServiceSkeleton parent;

        /* weak references */
        KioskCompositor              *compositor;
        MetaDisplay                  *display;

        /* strong references */
        GHashTable                   *client_bus_watch_ids;
        GHashTable                   *grabbed_accelerators;

        /* handles */
        guint                         bus_id;
};

enum
{
        PROP_COMPOSITOR = 1,
        NUMBER_OF_PROPERTIES
};
static GParamSpec *kiosk_shell_service_properties[NUMBER_OF_PROPERTIES] = { NULL, };

static void kiosk_shell_dbus_service_interface_init (KioskShellDBusServiceIface *interface);

G_DEFINE_TYPE_WITH_CODE (KioskShellService,
                         kiosk_shell_service,
                         KIOSK_TYPE_SHELL_DBUS_SERVICE_SKELETON,
                         G_IMPLEMENT_INTERFACE (KIOSK_TYPE_SHELL_DBUS_SERVICE,
                                                kiosk_shell_dbus_service_interface_init));

static void kiosk_shell_service_set_property (GObject      *object,
                                              guint         property_id,
                                              const GValue *value,
                                              GParamSpec   *param_spec);
static void kiosk_shell_service_get_property (GObject    *object,
                                              guint       property_id,
                                              GValue     *value,
                                              GParamSpec *param_spec);

static void kiosk_shell_service_constructed (GObject *object);
static void kiosk_shell_service_dispose (GObject *object);

static void
kiosk_shell_service_class_init (KioskShellServiceClass *shell_service_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (shell_service_class);

        object_class->constructed = kiosk_shell_service_constructed;
        object_class->set_property = kiosk_shell_service_set_property;
        object_class->get_property = kiosk_shell_service_get_property;
        object_class->dispose = kiosk_shell_service_dispose;

        kiosk_shell_service_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                               "compositor",
                                                                               "compositor",
                                                                               KIOSK_TYPE_COMPOSITOR,
                                                                               G_PARAM_CONSTRUCT_ONLY
                                                                               | G_PARAM_WRITABLE
                                                                               | G_PARAM_STATIC_NAME
                                                                               | G_PARAM_STATIC_NICK
                                                                               | G_PARAM_STATIC_BLURB);
        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_shell_service_properties);
}

static void
kiosk_shell_service_set_property (GObject      *object,
                                  guint         property_id,
                                  const GValue *value,
                                  GParamSpec   *param_spec)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;

        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_shell_service_get_property (GObject    *object,
                                  guint       property_id,
                                  GValue     *value,
                                  GParamSpec *param_spec)
{
        switch (property_id) {
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_shell_service_dispose (GObject *object)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);

        kiosk_shell_service_stop (self);

        g_clear_pointer (&self->client_bus_watch_ids, g_hash_table_unref);
        g_clear_pointer (&self->grabbed_accelerators, g_hash_table_unref);

        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->compositor);

        G_OBJECT_CLASS (kiosk_shell_service_parent_class)->dispose (object);
}

static void
kiosk_shell_service_constructed (GObject *object)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);

        G_OBJECT_CLASS (kiosk_shell_service_parent_class)->constructed (object);

        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
}

static void
stop_watching_client (KioskShellService *self,
                      const char        *client_unique_name)
{
        guint bus_watch_id;

        bus_watch_id = GPOINTER_TO_UINT (g_hash_table_lookup (self->client_bus_watch_ids,
                                                              client_unique_name));
        if (bus_watch_id == 0) {
                return;
        }

        g_debug ("KioskShellService: No longer watching client %s", client_unique_name);

        g_bus_unwatch_name (bus_watch_id);
        g_hash_table_remove (self->client_bus_watch_ids, client_unique_name);
}

static void
stop_watching_clients (KioskShellService *self)
{
        GHashTableIter iter;
        gpointer key, value;

        g_debug ("KioskShellService: Dropping all client watches");

        g_hash_table_iter_init (&iter, self->client_bus_watch_ids);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                const char *client_unique_name = key;
                guint bus_watch_id = GPOINTER_TO_UINT (value);

                g_debug ("KioskShellService: No longer watching client %s", client_unique_name);
                g_bus_unwatch_name (bus_watch_id);
        }

        g_hash_table_remove_all (self->client_bus_watch_ids);
}

static void
on_client_vanished (GDBusConnection   *connection,
                    const char        *client_unique_name,
                    KioskShellService *self)
{
        GHashTableIter iter;
        gpointer key, value;

        g_debug ("KioskShellService: Client %s vanished", client_unique_name);

        g_hash_table_iter_init (&iter, self->grabbed_accelerators);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                guint action_id = GPOINTER_TO_UINT (key);
                const char *unique_name = value;

                if (g_strcmp0 (client_unique_name, unique_name) != 0) {
                        continue;
                }

                g_debug ("KioskShellService: Ungrabbing accelerator with id %d",
                         action_id);
        }

        stop_watching_client (self, client_unique_name);
}

static void
watch_client (KioskShellService *self,
              const char        *client_unique_name)
{
        guint bus_watch_id;

        if (g_hash_table_contains (self->client_bus_watch_ids,
                                   client_unique_name)) {
                return;
        }

        g_debug ("KioskShellService: Watching client %s", client_unique_name);

        bus_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
                                         client_unique_name,
                                         G_BUS_NAME_WATCHER_FLAGS_NONE,
                                         (GBusNameAppearedCallback) NULL,
                                         (GBusNameVanishedCallback)
                                         on_client_vanished,
                                         self,
                                         NULL);

        g_hash_table_insert (self->client_bus_watch_ids,
                             g_strdup (client_unique_name),
                             GUINT_TO_POINTER (bus_watch_id));
}

static guint
grab_accelerator_for_client (KioskShellService *self,
                             const char        *accelerator,
                             guint              mode_flags,
                             guint              grab_flags,
                             const char        *client_unique_name)
{
        guint action_id;

        g_debug ("KioskShellService: Grabbing accelerator '%s' with flags %x for client %s",
                 accelerator, grab_flags, client_unique_name);

        action_id = meta_display_grab_accelerator (self->display, accelerator, grab_flags);

        if (action_id == 0) {
                g_debug ("KioskShellService: Grabbing failed");
                return action_id;
        }

        watch_client (self, client_unique_name);
        g_hash_table_insert (self->grabbed_accelerators,
                             GUINT_TO_POINTER (action_id),
                             g_strdup (client_unique_name));

        return action_id;
}

static gboolean
ungrab_accelerator_for_client (KioskShellService *self,
                               guint              action_id,
                               const char        *client_unique_name)
{
        const char *grabbing_client;
        gboolean ungrab_succeeded;

        g_debug ("KioskShellService: Ungrabbing accelerator with id '%d' for client %s",
                 action_id, client_unique_name);

        grabbing_client = g_hash_table_lookup (self->grabbed_accelerators,
                                               GUINT_TO_POINTER (action_id));

        if (g_strcmp0 (grabbing_client, client_unique_name) != 0) {
                g_debug ("KioskShellService: Client %s does not have grab on accelerator with id '%d'", client_unique_name, action_id);
                return FALSE;
        }

        ungrab_succeeded = meta_display_ungrab_accelerator (self->display, action_id);

        if (ungrab_succeeded) {
                g_debug ("KioskShellService: Ungrab succeeded");
                g_hash_table_remove (self->grabbed_accelerators,
                                     GUINT_TO_POINTER (action_id));
        } else {
                g_debug ("KioskShellService: Ungrab failed");
        }

        return ungrab_succeeded;
}

static gboolean
kiosk_shell_service_handle_grab_accelerator (KioskShellDBusService *object,
                                             GDBusMethodInvocation *invocation,
                                             const char            *accelerator,
                                             guint                  mode_flags,
                                             guint                  grab_flags)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);
        const char *client_unique_name;
        guint action_id;

        g_debug ("KioskShellService: Handling GrabAccelerator(%s, %x, %x) call",
                 accelerator, mode_flags, grab_flags);

        client_unique_name = g_dbus_method_invocation_get_sender (invocation);
        action_id = grab_accelerator_for_client (self, accelerator, mode_flags, grab_flags, client_unique_name);

        kiosk_shell_dbus_service_complete_grab_accelerator (KIOSK_SHELL_DBUS_SERVICE (self),
                                                            invocation,
                                                            action_id);

        return TRUE;
}

static gboolean
kiosk_shell_service_handle_grab_accelerators (KioskShellDBusService *object,
                                              GDBusMethodInvocation *invocation,
                                              GVariant              *accelerators)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);
        g_autoptr (GVariantIter) iter = NULL;
        GVariantBuilder builder;
        const char *client_unique_name;
        const char *accelerator;
        guint mode_flags;
        guint grab_flags;

        g_debug ("KioskShellService: Handling GrabAccelerators() call");

        client_unique_name = g_dbus_method_invocation_get_sender (invocation);

        g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));

        g_variant_get (accelerators, "a(suu)", &iter);
        while (g_variant_iter_loop (iter, "(suu)", &accelerator, &mode_flags, &grab_flags)) {
                guint action_id;

                action_id = grab_accelerator_for_client (self, accelerator, mode_flags, grab_flags, client_unique_name);

                g_variant_builder_add (&builder, "u", g_variant_new_uint32 (action_id));
        }

        kiosk_shell_dbus_service_complete_grab_accelerators (KIOSK_SHELL_DBUS_SERVICE (self),
                                                             invocation,
                                                             g_variant_builder_end (&builder));

        return TRUE;
}

static gboolean
kiosk_shell_service_handle_ungrab_accelerator (KioskShellDBusService *object,
                                               GDBusMethodInvocation *invocation,
                                               guint                  action_id)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);
        const char *client_unique_name;
        gboolean ungrab_succeeded;

        g_debug ("KioskShellService: Handling UngrabAccelerator(%d) call",
                 action_id);

        client_unique_name = g_dbus_method_invocation_get_sender (invocation);

        ungrab_succeeded = ungrab_accelerator_for_client (self, action_id, client_unique_name);

        kiosk_shell_dbus_service_complete_ungrab_accelerator (KIOSK_SHELL_DBUS_SERVICE (self),
                                                              invocation,
                                                              ungrab_succeeded);
        return TRUE;
}

static gboolean
kiosk_shell_service_handle_ungrab_accelerators (KioskShellDBusService *object,
                                                GDBusMethodInvocation *invocation,
                                                GVariant              *action_ids)
{
        KioskShellService *self = KIOSK_SHELL_SERVICE (object);
        const char *client_unique_name;
        guint action_id;

        g_autoptr (GVariantIter) iter = NULL;
        gboolean ungrab_succeeded = TRUE;

        g_debug ("KioskShellService: Handling UngrabAccelerators() call");

        client_unique_name = g_dbus_method_invocation_get_sender (invocation);

        g_variant_get (action_ids, "au", &iter);
        while (g_variant_iter_loop (iter, "u", &action_id)) {
                ungrab_succeeded &= ungrab_accelerator_for_client (self, action_id, client_unique_name);
        }

        kiosk_shell_dbus_service_complete_ungrab_accelerator (KIOSK_SHELL_DBUS_SERVICE (self),
                                                              invocation,
                                                              ungrab_succeeded);

        return TRUE;
}

static void
kiosk_shell_dbus_service_interface_init (KioskShellDBusServiceIface *interface)
{
        interface->handle_grab_accelerator = kiosk_shell_service_handle_grab_accelerator;
        interface->handle_grab_accelerators = kiosk_shell_service_handle_grab_accelerators;
        interface->handle_ungrab_accelerator = kiosk_shell_service_handle_ungrab_accelerator;
        interface->handle_ungrab_accelerators = kiosk_shell_service_handle_ungrab_accelerators;
}

static void
kiosk_shell_service_init (KioskShellService *self)
{
        g_debug ("KioskShellService: Initializing");
        self->grabbed_accelerators = g_hash_table_new_full (NULL, NULL, NULL, g_free);
        self->client_bus_watch_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}

KioskShellService *
kiosk_shell_service_new (KioskCompositor *compositor)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_SHELL_SERVICE,
                               "compositor", compositor,
                               NULL);

        return KIOSK_SHELL_SERVICE (object);
}

static void
on_user_bus_acquired (GDBusConnection   *connection,
                      const char        *unique_name,
                      KioskShellService *self)
{
        g_autoptr (GError) error = NULL;

        g_debug ("KioskShellService: Connected to user bus");

        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self),
                                          connection,
                                          KIOSK_SHELL_SERVICE_OBJECT_PATH,
                                          &error);

        if (error != NULL) {
                g_debug ("KioskShellService: Could not export interface skeleton: %s",
                         error->message);
                g_clear_error (&error);
        }
}

static void
on_bus_name_acquired (GDBusConnection   *connection,
                      const char        *name,
                      KioskShellService *self)
{
        if (g_strcmp0 (name, KIOSK_SHELL_SERVICE_BUS_NAME) != 0) {
                return;
        }

        g_debug ("KioskShellService: Acquired name %s", name);
}

static void
on_bus_name_lost (GDBusConnection   *connection,
                  const char        *name,
                  KioskShellService *self)
{
        if (g_strcmp0 (name, KIOSK_SHELL_SERVICE_BUS_NAME) != 0) {
                return;
        }

        g_debug ("KioskShellService: Lost name %s", name);
}

static void
on_accelerator_activated (KioskShellService  *self,
                          guint               action_id,
                          ClutterInputDevice *device,
                          guint32             timestamp)
{
        GVariantBuilder builder;
        const char *grabbing_client;
        const char *device_node;

        g_debug ("KioskShellService: Accelerator with id '%d' activated",
                 action_id);

        grabbing_client = g_hash_table_lookup (self->grabbed_accelerators,
                                               GUINT_TO_POINTER (action_id));

        if (grabbing_client == NULL) {
                g_debug ("KioskShellService: No grabbing client, so ignoring");
                return;
        }

        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
        g_variant_builder_add (&builder, "{sv}", "timestamp", g_variant_new_uint32 (timestamp));

        device_node = clutter_input_device_get_device_node (device);

        if (device_node != NULL) {
                g_variant_builder_add (&builder, "{sv}", "device-node", g_variant_new_string (device_node));
        }

        kiosk_shell_dbus_service_emit_accelerator_activated (KIOSK_SHELL_DBUS_SERVICE (self),
                                                             action_id,
                                                             g_variant_builder_end (&builder));
}

gboolean
kiosk_shell_service_start (KioskShellService *self,
                           GError           **error)
{
        g_return_val_if_fail (KIOSK_IS_SHELL_SERVICE (self), FALSE);

        g_debug ("KioskShellService: Starting");
        self->bus_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                                       KIOSK_SHELL_SERVICE_BUS_NAME,
                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
                                       (GBusAcquiredCallback) on_user_bus_acquired,
                                       (GBusNameAcquiredCallback) on_bus_name_acquired,
                                       (GBusNameVanishedCallback) on_bus_name_lost,
                                       self,
                                       NULL);

        g_signal_connect_swapped (self->display,
                                  "accelerator-activated",
                                  G_CALLBACK (on_accelerator_activated),
                                  self);
        return TRUE;
}

void
kiosk_shell_service_stop (KioskShellService *self)
{
        g_return_if_fail (KIOSK_IS_SHELL_SERVICE (self));

        g_debug ("KioskShellService: Stopping");

        g_signal_handlers_disconnect_by_func (self->display, on_accelerator_activated, self);

        stop_watching_clients (self);
        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self));
        g_clear_handle_id (&self->bus_id, g_bus_unown_name);
}
07070100000027000081A40000000000000000000000016506F4B700000294000000000000000000000000000000000000003200000000gnome-kiosk-45.0/compositor/kiosk-shell-service.h#pragma once

#include <glib-object.h>

#include "org.gnome.Shell.h"

typedef struct _KioskCompositor KioskCompositor;

G_BEGIN_DECLS

#define KIOSK_TYPE_SHELL_SERVICE (kiosk_shell_service_get_type ())

G_DECLARE_FINAL_TYPE (KioskShellService,
                      kiosk_shell_service,
                      KIOSK, SHELL_SERVICE,
                      KioskShellDBusServiceSkeleton);

KioskShellService *kiosk_shell_service_new (KioskCompositor *compositor);
gboolean kiosk_shell_service_start (KioskShellService *service,
                                    GError           **error);
void kiosk_shell_service_stop (KioskShellService *service);

G_END_DECLS
07070100000028000081A40000000000000000000000016506F4B700005476000000000000000000000000000000000000003700000000gnome-kiosk-45.0/compositor/kiosk-x-keyboard-manager.c#include "config.h"
#include "kiosk-x-keyboard-manager.h"

#include <stdlib.h>
#include <string.h>

#include <meta/display.h>
#include <meta/util.h>

#include <meta/meta-backend.h>
#include <meta/meta-context.h>
#include <meta/meta-x11-display.h>
#include <meta/meta-x11-errors.h>

#include <X11/Xatom.h>
#include <X11/XKBlib.h>

#include "kiosk-compositor.h"
#include "kiosk-gobject-utils.h"

struct _KioskXKeyboardManager
{
        GObject          parent;

        /* weak references */
        KioskCompositor *compositor;
        MetaBackend     *backend;
        MetaDisplay     *display;
        MetaContext     *context;
        Display         *x_server_display;

        /* strong references */
        GCancellable    *cancellable;
        GBytes          *xkb_rules_names_data;
        char           **layouts;
        char            *options;

        /* state */
        Window           x_server_root_window;
        Atom             xkb_rules_names_atom;
        int              xkb_event_base;

        size_t           layout_index;
        ssize_t          pending_layout_index;

        /* flags */
        guint32          xkb_rules_names_data_changed : 1;
};

enum
{
        PROP_COMPOSITOR = 1,
        PROP_LAYOUTS,
        PROP_SELECTED_LAYOUT,
        NUMBER_OF_PROPERTIES
};

static GParamSpec *kiosk_x_keyboard_manager_properties[NUMBER_OF_PROPERTIES] = { NULL, };

G_DEFINE_TYPE (KioskXKeyboardManager, kiosk_x_keyboard_manager, G_TYPE_OBJECT)

static void kiosk_x_keyboard_manager_set_property (GObject      *object,
                                                   guint         property_id,
                                                   const GValue *value,
                                                   GParamSpec   *param_spec);
static void kiosk_x_keyboard_manager_get_property (GObject    *object,
                                                   guint       property_id,
                                                   GValue     *value,
                                                   GParamSpec *param_spec);

static void kiosk_x_keyboard_manager_constructed (GObject *object);
static void kiosk_x_keyboard_manager_dispose (GObject *object);

KioskXKeyboardManager *
kiosk_x_keyboard_manager_new (KioskCompositor *compositor)
{
        GObject *object;

        object = g_object_new (KIOSK_TYPE_X_KEYBOARD_MANAGER,
                               "compositor", compositor,
                               NULL);

        return KIOSK_X_KEYBOARD_MANAGER (object);
}

static void
kiosk_x_keyboard_manager_class_init (KioskXKeyboardManagerClass *x_keyboard_manager_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (x_keyboard_manager_class);

        object_class->constructed = kiosk_x_keyboard_manager_constructed;
        object_class->set_property = kiosk_x_keyboard_manager_set_property;
        object_class->get_property = kiosk_x_keyboard_manager_get_property;
        object_class->dispose = kiosk_x_keyboard_manager_dispose;

        kiosk_x_keyboard_manager_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
                                                                                    "compositor",
                                                                                    "compositor",
                                                                                    KIOSK_TYPE_COMPOSITOR,
                                                                                    G_PARAM_CONSTRUCT_ONLY
                                                                                    | G_PARAM_WRITABLE
                                                                                    | G_PARAM_STATIC_NAME
                                                                                    | G_PARAM_STATIC_NICK
                                                                                    | G_PARAM_STATIC_BLURB);
        kiosk_x_keyboard_manager_properties[PROP_SELECTED_LAYOUT] = g_param_spec_string ("selected-layout",
                                                                                         "selected-layout",
                                                                                         "selected-layout",
                                                                                         NULL,
                                                                                         G_PARAM_READABLE
                                                                                         | G_PARAM_STATIC_NAME
                                                                                         | G_PARAM_STATIC_NICK
                                                                                         | G_PARAM_STATIC_BLURB);

        kiosk_x_keyboard_manager_properties[PROP_LAYOUTS] = g_param_spec_boxed ("layouts",
                                                                                "layouts",
                                                                                "layouts",
                                                                                G_TYPE_STRV,
                                                                                G_PARAM_READABLE
                                                                                | G_PARAM_STATIC_NAME
                                                                                | G_PARAM_STATIC_NICK
                                                                                | G_PARAM_STATIC_BLURB);

        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_x_keyboard_manager_properties);
}

static void
kiosk_x_keyboard_manager_set_property (GObject      *object,
                                       guint         property_id,
                                       const GValue *value,
                                       GParamSpec   *param_spec)
{
        KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);

        switch (property_id) {
        case PROP_COMPOSITOR:
                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static void
kiosk_x_keyboard_manager_get_property (GObject    *object,
                                       guint       property_id,
                                       GValue     *value,
                                       GParamSpec *param_spec)
{
        KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);

        switch (property_id) {
        case PROP_SELECTED_LAYOUT:
                g_value_set_string (value, self->layouts[self->layout_index]);
                break;
        case PROP_LAYOUTS:
                g_value_set_boxed (value, self->layouts);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
                break;
        }
}

static char **
qualify_layouts_with_variants (KioskXKeyboardManager *self,
                               const char * const    *layouts,
                               const char * const    *variants)
{
        size_t number_of_layouts = 0;
        size_t number_of_variants = 0;
        char **fully_qualified_layouts = NULL;

        size_t i, j;

        g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), FALSE);

        number_of_layouts = g_strv_length ((GStrv) layouts);
        number_of_variants = g_strv_length ((GStrv) variants);

        if (number_of_layouts < number_of_variants) {
                g_debug ("KioskXKeyboardManager: There is a layout variant mismatch");
                return NULL;
        }

        fully_qualified_layouts = g_new0 (char *, number_of_layouts + 1);

        for (i = 0, j = 0; layouts[i] != NULL; i++) {
                const char *layout = layouts[i];
                const char *variant = "";

                if (variants[j] != NULL) {
                        variant = variants[j++];
                }

                if (variant[0] == '\0') {
                        fully_qualified_layouts[i] = g_strdup (layout);
                } else {
                        fully_qualified_layouts[i] = g_strdup_printf ("%s+%s", layout, variant);
                }
        }

        return fully_qualified_layouts;
}

static void
kiosk_x_keyboard_manager_set_layout_index (KioskXKeyboardManager *self,
                                           size_t                 layout_index)
{
        size_t number_of_layouts;

        if (self->layout_index == layout_index) {
                return;
        }

        g_debug ("KioskXKeyboardManager: X server is using layout with index %ld",
                 layout_index);

        number_of_layouts = g_strv_length (self->layouts);

        if (layout_index >= number_of_layouts) {
                layout_index = 0;
        }

        self->layout_index = layout_index;
        g_object_notify (G_OBJECT (self), "selected-layout");
}

static gboolean
kiosk_x_keyboard_manager_read_current_layout_index (KioskXKeyboardManager *self)
{
        XkbStateRec xkb_state = { 0 };
        int status;

        status = XkbGetState (self->x_server_display, XkbUseCoreKbd, &xkb_state);

        if (status != Success) {
                g_debug ("KioskXKeyboardManager: Could not read current layout index");
                return FALSE;
        }

        kiosk_x_keyboard_manager_set_layout_index (self, xkb_state.locked_group);
        return FALSE;
}

static gboolean
kiosk_x_keyboard_manager_read_xkb_rules_names_data (KioskXKeyboardManager *self)
{
        g_autoptr (GBytes) new_xkb_rules_names_data = NULL;
        g_autoptr (GVariant) input_source_group = NULL;
        size_t number_of_layouts = 0;
        g_autofree char *layouts_string = NULL;
        g_autofree char *variants_string = NULL;
        g_autofree char *options = NULL;
        g_auto (GStrv) layouts = NULL;
        g_auto (GStrv) variants = NULL;
        g_auto (GStrv) qualified_layouts = NULL;
        int status;
        Atom returned_type = 0;
        int returned_format = 0;
        gulong number_of_bytes_read = 0;
        gulong number_of_bytes_unread = 0;
        guchar *property_values;
        size_t i;
        enum
        {
                RULES_NAME = 0,
                MODEL,
                LAYOUTS,
                VARIANTS,
                OPTIONS
        } property_value_index;

        self->xkb_rules_names_data_changed = TRUE;

        g_debug ("KioskXKeyboardManager: Reading active keyboard layouts from X server");

        status = XGetWindowProperty (self->x_server_display,
                                     self->x_server_root_window,
                                     self->xkb_rules_names_atom,
                                     0, 1024, FALSE, XA_STRING,
                                     &returned_type,
                                     &returned_format,
                                     &number_of_bytes_read,
                                     &number_of_bytes_unread,
                                     &property_values);

        if (status != Success) {
                g_debug ("KioskXKeyboardManager: Could not read active keyboard layouts from X server");
                return FALSE;
        }

        if (returned_type != XA_STRING ||
            returned_format != 8 ||
            number_of_bytes_unread != 0) {
                g_debug ("KioskXKeyboardManager: Active keyboard layouts propery from X server is corrupted");
                return FALSE;
        }

        new_xkb_rules_names_data = g_bytes_new_with_free_func (property_values,
                                                               number_of_bytes_read,
                                                               (GDestroyNotify) XFree,
                                                               NULL);

        property_value_index = 0;
        for (i = 0; i < number_of_bytes_read; i++) {
                g_autofree char *value = g_strdup ((char *) property_values + i);
                size_t value_length = strlen (value);

                switch (property_value_index) {
                case RULES_NAME:
                case MODEL:
                        break;
                case LAYOUTS:
                        layouts_string = g_steal_pointer (&value);
                        g_debug ("KioskXKeyboardManager: Read layouts '%s'", layouts_string);
                        break;
                case VARIANTS:
                        variants_string = g_steal_pointer (&value);
                        g_debug ("KioskXKeyboardManager: Read variants '%s'", variants_string);
                        break;
                case OPTIONS:
                        options = g_steal_pointer (&value);
                        g_debug ("KioskXKeyboardManager: Read options '%s'", options);
                        break;
                }

                i += value_length;
                property_value_index++;
        }

        if (self->xkb_rules_names_data != NULL && g_bytes_equal (self->xkb_rules_names_data, new_xkb_rules_names_data)) {
                g_debug ("KioskXKeyboardManager: XKB rules names data is unchanged");
                return FALSE;
        }

        g_clear_pointer (&self->xkb_rules_names_data, g_bytes_unref);
        self->xkb_rules_names_data = g_steal_pointer (&new_xkb_rules_names_data);

        layouts = g_strsplit (layouts_string, ",", -1);
        variants = g_strsplit (variants_string, ",", -1);

        qualified_layouts = qualify_layouts_with_variants (self, (const char * const *) layouts, (const char * const *) variants);

        if (qualified_layouts == NULL) {
                g_debug ("KioskXKeyboardManager: Unable to qualify layouts with variants");
                return FALSE;
        }

        number_of_layouts = g_strv_length (qualified_layouts);

        if (number_of_layouts == 0) {
                g_debug ("KioskXKeyboardManager: No layouts found");
                return FALSE;
        }

        g_clear_pointer (&self->layouts, g_strfreev);
        self->layouts = g_steal_pointer (&qualified_layouts);
        self->options = g_steal_pointer (&options);

        g_object_freeze_notify (G_OBJECT (self));
        g_object_notify (G_OBJECT (self), "layouts");
        kiosk_x_keyboard_manager_read_current_layout_index (self);
        g_object_thaw_notify (G_OBJECT (self));

        return TRUE;
}

static void
monitor_x_server_display_for_changes (KioskXKeyboardManager *self)
{
        int major = XkbMajorVersion;
        int minor = XkbMinorVersion;
        XWindowAttributes attributes;

        XGetWindowAttributes (self->x_server_display, self->x_server_root_window, &attributes);

        if (!(attributes.your_event_mask & PropertyChangeMask)) {
                XSelectInput (self->x_server_display,
                              self->x_server_root_window,
                              attributes.your_event_mask | PropertyChangeMask);
        }

        XkbQueryExtension (self->x_server_display, NULL, &self->xkb_event_base, NULL, &major, &minor);
        self->xkb_rules_names_atom = XInternAtom (self->x_server_display, "_XKB_RULES_NAMES", False);
}

static void
kiosk_x_keyboard_manager_handle_x_server_property_notify (KioskXKeyboardManager *self,
                                                          XPropertyEvent        *x_server_event)
{
        if (x_server_event->window != self->x_server_root_window) {
                return;
        }

        if (x_server_event->atom != self->xkb_rules_names_atom) {
                return;
        }

        g_debug ("KioskXKeyboardManager: XKB rules names property changed in X server");
        kiosk_x_keyboard_manager_read_xkb_rules_names_data (self);
}

static void
kiosk_x_keyboard_manager_handle_xkb_event (KioskXKeyboardManager *self,
                                           XkbEvent              *x_server_event)
{
        size_t layout_index;

        layout_index = XkbStateGroup (&x_server_event->state);
        switch (x_server_event->any.xkb_type) {
        case XkbStateNotify:
                if (!(x_server_event->state.changed & XkbGroupStateMask)) {
                        return;
                }

                /* Mutter immediately reverts all layout changes coming from
                 * the outside, so we hide the event from it.
                 */
                x_server_event->state.changed &= ~XkbGroupLockMask;

                if (self->xkb_rules_names_data_changed) {
                        g_debug ("KioskXKeyboardManager: Ignoring spurious group change following layout change");
                        self->xkb_rules_names_data_changed = FALSE;
                        return;
                }
                g_debug ("KioskXKeyboardManager: Approving keyboard group change to group %lu", layout_index);
                kiosk_x_keyboard_manager_set_layout_index (self, layout_index);
                break;
        }
}

static void
on_x_server_event (KioskXKeyboardManager *self,
                   XEvent                *x_server_event)
{
        if (self->x_server_display == NULL) {
                self->x_server_display = x_server_event->xany.display;
                self->x_server_root_window = DefaultRootWindow (self->x_server_display);
                monitor_x_server_display_for_changes (self);
        }

        switch (x_server_event->type) {
        case PropertyNotify:
                kiosk_x_keyboard_manager_handle_x_server_property_notify (self, &x_server_event->xproperty);
                break;
        default:
                if (x_server_event->type == self->xkb_event_base) {
                        kiosk_x_keyboard_manager_handle_xkb_event (self, (XkbEvent *) x_server_event);
                }
                break;
        }
}

const char * const *
kiosk_x_keyboard_manager_get_layouts (KioskXKeyboardManager *self)
{
        g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);

        return (const char * const *) self->layouts;
}

const char *
kiosk_x_keyboard_manager_get_selected_layout (KioskXKeyboardManager *self)
{
        g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);

        if (self->layouts == NULL) {
                return NULL;
        }

        g_debug ("KioskXKeyboardManager: Selected layout is '%s'", self->layouts[self->layout_index]);

        return self->layouts[self->layout_index];
}

const char *
kiosk_x_keyboard_manager_get_options (KioskXKeyboardManager *self)
{
        g_return_val_if_fail (KIOSK_IS_X_KEYBOARD_MANAGER (self), NULL);

        return self->options;
}

gboolean
kiosk_x_keyboard_manager_keymap_is_active (KioskXKeyboardManager *self,
                                           const char * const    *layouts,
                                           const char * const    *variants,
                                           const char            *options)
{
        g_auto (GStrv) qualified_layouts = NULL;

        if (g_strcmp0 (options, self->options) != 0) {
                return FALSE;
        }

        qualified_layouts = qualify_layouts_with_variants (self, layouts, variants);

        if (qualified_layouts == NULL) {
                return FALSE;
        }

        if (!g_strv_equal ((const char * const *) qualified_layouts, (const char * const *) self->layouts)) {
                return FALSE;
        }

        return TRUE;
}

gboolean
kiosk_x_keyboard_manager_layout_group_is_locked (KioskXKeyboardManager *self,
                                                 xkb_layout_index_t     layout_index)
{
        return self->layout_index == layout_index;
}

static void
kiosk_x_keyboard_manager_init (KioskXKeyboardManager *self)
{
}

static void
kiosk_x_keyboard_manager_constructed (GObject *object)
{
        KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);

        g_debug ("KioskXKeyboardManager: Initializing");

        G_OBJECT_CLASS (kiosk_x_keyboard_manager_parent_class)->constructed (object);

        self->cancellable = g_cancellable_new ();

        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
        g_set_weak_pointer (&self->backend, meta_context_get_backend (self->context));

        self->pending_layout_index = -1;

        g_signal_connect_object (G_OBJECT (self->compositor),
                                 "x-server-event",
                                 G_CALLBACK (on_x_server_event),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
kiosk_x_keyboard_manager_dispose (GObject *object)
{
        KioskXKeyboardManager *self = KIOSK_X_KEYBOARD_MANAGER (object);

        g_debug ("KioskXKeyboardManager: Disposing");

        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        g_clear_pointer (&self->xkb_rules_names_data, g_bytes_unref);
        g_clear_pointer (&self->layouts, g_strfreev);
        g_clear_pointer (&self->options, g_free);

        g_clear_weak_pointer (&self->display);
        g_clear_weak_pointer (&self->context);
        g_clear_weak_pointer (&self->backend);
        g_clear_weak_pointer (&self->compositor);

        G_OBJECT_CLASS (kiosk_x_keyboard_manager_parent_class)->dispose (object);
}
07070100000029000081A40000000000000000000000016506F4B7000004FD000000000000000000000000000000000000003700000000gnome-kiosk-45.0/compositor/kiosk-x-keyboard-manager.h#pragma once

#include <glib-object.h>
#include <xkbcommon/xkbcommon.h>

typedef struct _KioskCompositor KioskCompositor;

G_BEGIN_DECLS

#define KIOSK_TYPE_X_KEYBOARD_MANAGER (kiosk_x_keyboard_manager_get_type ())

G_DECLARE_FINAL_TYPE (KioskXKeyboardManager,
                      kiosk_x_keyboard_manager,
                      KIOSK, X_KEYBOARD_MANAGER,
                      GObject);

KioskXKeyboardManager *kiosk_x_keyboard_manager_new (KioskCompositor *compositor);

const char * const *kiosk_x_keyboard_manager_get_layouts (KioskXKeyboardManager *manager);
const char *kiosk_x_keyboard_manager_get_selected_layout (KioskXKeyboardManager *manager);
const char *kiosk_x_keyboard_manager_get_options (KioskXKeyboardManager *manager);
gboolean kiosk_x_keyboard_manager_keymap_is_active (KioskXKeyboardManager *manager,
                                                    const char * const    *layouts,
                                                    const char * const    *variants,
                                                    const char            *options);
gboolean kiosk_x_keyboard_manager_layout_group_is_locked (KioskXKeyboardManager *manager,
                                                          xkb_layout_index_t     layout_index);

G_END_DECLS
0707010000002A000081A40000000000000000000000016506F4B700000AF3000000000000000000000000000000000000002300000000gnome-kiosk-45.0/compositor/main.c#include "config.h"

#include <stdlib.h>
#include <string.h>

#include <glib-unix.h>
#include <glib/gi18n.h>

#include <meta/meta-context.h>
#include <meta/meta-plugin.h>
#include <meta/prefs.h>

#include "kiosk-compositor.h"

static gboolean
print_version (const gchar *option_name,
               const gchar *value,
               gpointer     data,
               GError     **error)
{
        g_print ("Kiosk %s\n", VERSION);
        exit (0);
}

static GOptionEntry
        kiosk_options[] = {
        {
                "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
                print_version,
                N_ ("Print version"),
                NULL
        },
        { NULL }
};

static void
set_working_directory (void)
{
        const char *working_directory;
        int result;

        working_directory = g_get_home_dir ();

        if (working_directory == NULL)
                working_directory = "/";

        result = chdir (working_directory);

        if (result != 0) {
                g_warning ("Could not change working directory to '%s': %m",
                           working_directory);
        }
}

static void
set_dconf_profile (void)
{
        setenv ("DCONF_PROFILE", "gnomekiosk", TRUE);
}

static gboolean
on_termination_signal (MetaContext *context)
{
        meta_context_terminate (context);

        return G_SOURCE_REMOVE;
}

int
main (int    argc,
      char **argv)
{
        g_autoptr (MetaContext) context = NULL;
        g_autoptr (GError) error = NULL;

        bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
        textdomain (GETTEXT_PACKAGE);

        signal (SIGPIPE, SIG_IGN);

        set_working_directory ();
        set_dconf_profile ();

        context = meta_create_context ("Kiosk");
        meta_context_add_option_entries (context, kiosk_options, GETTEXT_PACKAGE);
        if (!meta_context_configure (context, &argc, &argv, &error)) {
                g_printerr ("%s: Configuration failed: %s\n", argv[0], error->message);
                exit (1);
        }

        meta_context_set_plugin_gtype (context, KIOSK_TYPE_COMPOSITOR);

        if (!meta_context_setup (context, &error)) {
                g_printerr ("%s: Setup failed: %s\n", argv[0], error->message);
                exit (1);
        }

        if (!meta_context_start (context, &error)) {
                g_printerr ("%s: Failed to start: %s\n", argv[0], error->message);
                exit (1);
        }

        g_unix_signal_add (SIGTERM, (GSourceFunc) on_termination_signal, context);

        if (!meta_context_run_main_loop (context, &error)) {
                g_printerr ("%s: Quit unexpectedly: %s\n", argv[0], error->message);
                exit (1);
        }

        return 0;
}
0707010000002B000081A40000000000000000000000016506F4B700000049000000000000000000000000000000000000002000000000gnome-kiosk-45.0/config.h.meson#mesondefine GETTEXT_PACKAGE
#mesondefine VERSION
#mesondefine LOCALEDIR
0707010000002C000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002100000000gnome-kiosk-45.0/dbus-interfaces0707010000002D000081A40000000000000000000000016506F4B7000004DC000000000000000000000000000000000000003D00000000gnome-kiosk-45.0/dbus-interfaces/org.freedesktop.locale1.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
 <interface name="org.freedesktop.locale1">
  <property name="Locale" type="as" access="read">
  </property>
  <property name="X11Layout" type="s" access="read">
  </property>
  <property name="X11Model" type="s" access="read">
  </property>
  <property name="X11Variant" type="s" access="read">
  </property>
  <property name="X11Options" type="s" access="read">
  </property>
  <property name="VConsoleKeymap" type="s" access="read">
  </property>
  <property name="VConsoleKeymapToggle" type="s" access="read">
  </property>
  <method name="SetLocale">
   <arg type="as" direction="in"/>
   <arg type="b" direction="in"/>
  </method>
  <method name="SetVConsoleKeyboard">
   <arg type="s" direction="in"/>
   <arg type="s" direction="in"/>
   <arg type="b" direction="in"/>
   <arg type="b" direction="in"/>
  </method>
  <method name="SetX11Keyboard">
   <arg type="s" direction="in"/>
   <arg type="s" direction="in"/>
   <arg type="s" direction="in"/>
   <arg type="s" direction="in"/>
   <arg type="b" direction="in"/>
   <arg type="b" direction="in"/>
  </method>
 </interface>
</node>
0707010000002E000081A40000000000000000000000016506F4B7000002BA000000000000000000000000000000000000004600000000gnome-kiosk-45.0/dbus-interfaces/org.gnome.DisplayManager.Manager.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                      "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.56.1 -->
<node>
  <interface name="org.gnome.DisplayManager.Manager">
    <method name="RegisterDisplay">
      <arg type="a{ss}" name="details" direction="in"/>
    </method>
    <method name="OpenSession">
      <arg type="s" name="address" direction="out"/>
    </method>
    <method name="OpenReauthenticationChannel">
      <arg type="s" name="username" direction="in"/>
      <arg type="s" name="address" direction="out"/>
    </method>
    <property type="s" name="Version" access="read"/>
  </interface>
</node>
0707010000002F000081A40000000000000000000000016506F4B700000ED4000000000000000000000000000000000000003500000000gnome-kiosk-45.0/dbus-interfaces/org.gnome.Kiosk.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                      "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
  <interface name="org.gnome.Kiosk"/>
  <interface name="org.gnome.Kiosk.InputSources">
    <method name="SetInputSources">
        <arg name="input_sources" type="a(ss)" direction="in">
            <doc:doc>
               <doc:summary>A (backend_type,backend_id) list of XKB layouts and IBus input engines.</doc:summary>
               <doc:description>
                   The backend type can be either "xkb" or "ibus".
                        - If the type is "xkb" the id should be of the form "layout" or
                          "layout+variant"
                        - If the type is "ibus" the id should be an ibus engine name like
                          "libpinyin" or "m17n:ur:phonetic"
               </doc:description>
            </doc:doc>
        </arg>
        <arg name="options" type="as" direction="in">
            <doc:summary>A list of XKB options to apply (for instance 'compose:ralt').</doc:summary>
        </arg>
        <doc:doc>
            <doc:description>
                Enables the passed in XKB keyboard layouts and IBus engines for the session.
            </doc:description>
        </doc:doc>
    </method>
    <method name="SetInputSourcesFromLocales">
        <arg name="locales" type="as" direction="in">
           <doc:summary>A list of locales to add keyboard layouts and input engines for (for instance 'bn_IN').</doc:summary>
        </arg>
        <arg name="options" type="as" direction="in">
            <doc:summary>A list of XKB options to apply (for instance 'compose:ralt').</doc:summary>
        </arg>
        <doc:doc>
            <doc:description>
                 Enables appropriate XKB keyboard layouts and IBus engines for the session
                 given the passed locales.
            </doc:description>
        </doc:doc>
    </method>
    <method name="SetInputSourcesFromSessionConfiguration">
        <doc:doc>
            <doc:description>
                Enables the XKB keyboard layouts and IBus engines configured for the
                session via the "org.gnome.desktop.input-sources sources" and
                "org.gnome.desktop.input-sources xkb-options" gsettings.  If the session
                has no configured input sources, it falls back to querying localed.
            </doc:description>
        </doc:doc>
    </method>
    <method name="SelectInputSource">
        <arg name="input_source" type="o" direction="in"/>
        <doc:doc>
            <doc:description>
                Selects which input source from the current list of set input sources is
                active.
            </doc:description>
        </doc:doc>
    </method>
    <method name="SelectNextInputSource">
        <doc:doc>
            <doc:description>
                Selects the next input source in the list of active input sources.
            </doc:description>
        </doc:doc>
    </method>
    <method name="SelectPreviousInputSource">
        <doc:doc>
            <doc:description>
                Selects the next input source in the list of active input sources.
            </doc:description>
        </doc:doc>
    </method>
    <property name="SelectedInputSource" type="o" access="read"/>
    <property name="InputSources" type="ao" access="read"/>
  </interface>
  <interface name="org.gnome.Kiosk.InputSources.InputSource">
    <property name="ShortName" type="s" access="read"/>
    <property name="FullName" type="s" access="read"/>
    <property name="BackendType" type="s" access="read"/>
    <property name="BackendId" type="s" access="read"/>
  </interface>
</node>
07070100000030000081A40000000000000000000000016506F4B700000C93000000000000000000000000000000000000003E00000000gnome-kiosk-45.0/dbus-interfaces/org.gnome.SessionManager.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                      "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.66.7 -->
<node>
  <interface name="org.gnome.SessionManager">
    <method name="Setenv">
      <arg type="s" name="variable" direction="in"/>
      <arg type="s" name="value" direction="in"/>
    </method>
    <method name="GetLocale">
      <arg type="i" name="category" direction="in"/>
      <arg type="s" name="value" direction="out"/>
    </method>
    <method name="InitializationError">
      <arg type="s" name="message" direction="in"/>
      <arg type="b" name="fatal" direction="in"/>
    </method>
    <method name="Initialized"/>
    <method name="RegisterClient">
      <arg type="s" name="app_id" direction="in"/>
      <arg type="s" name="client_startup_id" direction="in"/>
      <arg type="o" name="client_id" direction="out"/>
    </method>
    <method name="UnregisterClient">
      <arg type="o" name="client_id" direction="in"/>
    </method>
    <method name="Inhibit">
      <arg type="s" name="app_id" direction="in"/>
      <arg type="u" name="toplevel_xid" direction="in"/>
      <arg type="s" name="reason" direction="in"/>
      <arg type="u" name="flags" direction="in"/>
      <arg type="u" name="inhibit_cookie" direction="out"/>
    </method>
    <method name="Uninhibit">
      <arg type="u" name="inhibit_cookie" direction="in"/>
    </method>
    <method name="IsInhibited">
      <arg type="u" name="flags" direction="in"/>
      <arg type="b" name="is_inhibited" direction="out"/>
    </method>
    <method name="GetClients">
      <arg type="ao" name="clients" direction="out"/>
    </method>
    <method name="GetInhibitors">
      <arg type="ao" name="inhibitors" direction="out"/>
    </method>
    <method name="IsAutostartConditionHandled">
      <arg type="s" name="condition" direction="in"/>
      <arg type="b" name="handled" direction="out"/>
    </method>
    <method name="Shutdown"/>
    <method name="Reboot"/>
    <method name="CanShutdown">
      <arg type="b" name="is_available" direction="out"/>
    </method>
    <method name="SetRebootToFirmwareSetup">
      <arg type="b" name="enable" direction="in"/>
    </method>
    <method name="CanRebootToFirmwareSetup">
      <arg type="b" name="is_available" direction="out"/>
    </method>
    <method name="Logout">
      <arg type="u" name="mode" direction="in"/>
    </method>
    <method name="IsSessionRunning">
      <arg type="b" name="running" direction="out"/>
    </method>
    <signal name="ClientAdded">
      <arg type="o" name="id"/>
    </signal>
    <signal name="ClientRemoved">
      <arg type="o" name="id"/>
    </signal>
    <signal name="InhibitorAdded">
      <arg type="o" name="id"/>
    </signal>
    <signal name="InhibitorRemoved">
      <arg type="o" name="id"/>
    </signal>
    <signal name="SessionRunning"/>
    <signal name="SessionOver"/>
    <property type="s" name="SessionName" access="read"/>
    <property type="s" name="Renderer" access="read"/>
    <property type="b" name="SessionIsActive" access="read"/>
    <property type="u" name="InhibitedActions" access="read"/>
  </interface>
</node>
07070100000031000081A40000000000000000000000016506F4B700000500000000000000000000000000000000000000003500000000gnome-kiosk-45.0/dbus-interfaces/org.gnome.Shell.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
                      "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.66.7 -->
<node>
  <interface name="org.gnome.Shell">
    <method name="GrabAccelerator">
      <arg type="s" name="accelerator" direction="in">
      </arg>
      <arg type="u" name="modeFlags" direction="in">
      </arg>
      <arg type="u" name="grabFlags" direction="in">
      </arg>
      <arg type="u" name="action" direction="out">
      </arg>
    </method>
    <method name="GrabAccelerators">
      <arg type="a(suu)" name="accelerators" direction="in">
      </arg>
      <arg type="au" name="actions" direction="out">
      </arg>
    </method>
    <method name="UngrabAccelerator">
      <arg type="u" name="action" direction="in">
      </arg>
      <arg type="b" name="success" direction="out">
      </arg>
    </method>
    <method name="UngrabAccelerators">
      <arg type="au" name="action" direction="in">
      </arg>
      <arg type="b" name="success" direction="out">
      </arg>
    </method>
    <signal name="AcceleratorActivated">
      <arg type="u" name="action">
      </arg>
      <arg type="a{sv}" name="parameters">
      </arg>
    </signal>
  </interface>
</node>
07070100000032000081A40000000000000000000000016506F4B700000346000000000000000000000000000000000000002200000000gnome-kiosk-45.0/gnome-kiosk.doap<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
         xmlns:foaf="http://xmlns.com/foaf/0.1/"
         xmlns:gnome="http://api.gnome.org/doap-extensions#"
         xmlns="http://usefulinc.com/ns/doap#">

  <name xml:lang="en">Kiosk</name>
  <shortdesc xml:lang="en">mutter based compositor for kiosks</shortdesc>
  <description>Kiosk provides a desktop enviroment suitable for fixed purpose,
  or single application deployments like wall displays and point-of-sale systems.
  </description>
  <programming-language>C</programming-language>

  <author>
    <foaf:Person>
      <foaf:name>Ray Strode </foaf:name>
      <foaf:mbox rdf:resource="mailto:rstrode@redhat.com" />
      <gnome:userid>halfline</gnome:userid>
    </foaf:Person>
  </author>
</Project>
07070100000033000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002000000000gnome-kiosk-45.0/input-selector07070100000034000081A40000000000000000000000016506F4B7000029FE000000000000000000000000000000000000004300000000gnome-kiosk-45.0/input-selector/kiosk-input-selector-application.c#include "kiosk-input-selector-application.h"

#include <stdlib.h>
#include <string.h>

#include <glib-object.h>
#include <gtk/gtk.h>

#include "org.gnome.Kiosk.h"

struct _KioskInputSelectorApplication
{
        GtkApplication            parent;

        /* weak references */
        GtkWidget                *window;
        GtkWidget                *input_sources_menu_button;
        GMenu                    *input_sources_menu;

        /* strong references */
        GCancellable             *cancellable;
        KioskInputSourcesManager *input_sources_manager;
        GDBusObjectManager       *object_manager;
};

G_DEFINE_TYPE (KioskInputSelectorApplication, kiosk_input_selector_application, GTK_TYPE_APPLICATION)

KioskInputSelectorApplication *
kiosk_input_selector_application_new (void){
        GObject *object;
        guint flags = G_APPLICATION_NON_UNIQUE
                      | G_APPLICATION_HANDLES_COMMAND_LINE;

        object = g_object_new (KIOSK_TYPE_INPUT_SELECTOR_APPLICATION,
                               "application-id", "org.gnome.Kiosk.InputSelector",
                               "flags", flags,
                               NULL);

        return KIOSK_INPUT_SELECTOR_APPLICATION (object);
}

static void
on_activate_switch_action (KioskInputSelectorApplication *self,
                           GVariant                      *parameter)
{
        const char *object_path;

        g_variant_get (parameter, "&o", &object_path);
        g_print ("activated source %s\n", object_path);

        kiosk_input_sources_manager_call_select_input_source_sync (self->input_sources_manager, object_path, NULL, NULL);
}

static void
set_menu_label_from_selected_input_source (KioskInputSelectorApplication *self)
{
        const char *object_path;
        g_autoptr (GDBusObject) object = NULL;
        g_autoptr (KioskInputSource) input_source = NULL;

        object_path = kiosk_input_sources_manager_get_selected_input_source (self->input_sources_manager);
        object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path);
        input_source = kiosk_object_get_input_source (KIOSK_OBJECT (object));

        gtk_menu_button_set_label (GTK_MENU_BUTTON (self->input_sources_menu_button), kiosk_input_source_get_short_name (input_source));

        g_debug ("KioskInputSelectorApplication: Marking input source %s ('%s', '%s') as selected",
                 object_path,
                 kiosk_input_source_get_backend_type (input_source),
                 kiosk_input_source_get_backend_id (input_source));
}

static void
populate_input_sources_menu_with_input_source_manager (KioskInputSelectorApplication *self)
{
        const char * const *object_paths;
        size_t i;

        gtk_menu_button_popdown (GTK_MENU_BUTTON (self->input_sources_menu_button));
        g_menu_remove_all (self->input_sources_menu);
        object_paths = kiosk_input_sources_manager_get_input_sources (self->input_sources_manager);
        for (i = 0; object_paths[i] != NULL; i++) {
                const char *object_path = object_paths[i];
                g_autoptr (GDBusObject) object = NULL;
                g_autoptr (KioskInputSource) input_source = NULL;
                g_autofree char *action_id;

                object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path);
                input_source = kiosk_object_get_input_source (KIOSK_OBJECT (object));

                g_debug ("KioskInputSelectorApplication: %s ('%s', '%s')",
                         object_path,
                         kiosk_input_source_get_backend_type (input_source),
                         kiosk_input_source_get_backend_id (input_source));

                action_id = g_action_print_detailed_name ("win.switch-input-source",
                                                          g_variant_new ("o", object_path));

                g_menu_append (self->input_sources_menu,
                               kiosk_input_source_get_full_name (input_source),
                               action_id);
        }
}

static void
synchronize_input_sources_menu_with_input_source_manager (KioskInputSelectorApplication *self)
{
        g_debug ("KioskInputSelectorApplication: Synchronizing menu with compositor state");
        set_menu_label_from_selected_input_source (self);
        populate_input_sources_menu_with_input_source_manager (self);
}

static void
create_switch_input_source_action (KioskInputSelectorApplication *self)
{
        g_autoptr (GSimpleAction) switch_action = NULL;

        switch_action = g_simple_action_new ("switch-input-source", G_VARIANT_TYPE ("o"));
        g_signal_connect_object (G_OBJECT (switch_action),
                                 "activate",
                                 G_CALLBACK (on_activate_switch_action),
                                 self,
                                 G_CONNECT_SWAPPED);

        g_action_map_add_action (G_ACTION_MAP (self->window), G_ACTION (switch_action));
}

static void
connect_to_input_source_manager (KioskInputSelectorApplication *self)
{
        g_autoptr (GDBusObject) manager_object = NULL;

        self->object_manager = kiosk_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION,
                                                                             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
                                                                             "org.gnome.Kiosk",
                                                                             "/org/gnome/Kiosk/InputSources",
                                                                             self->cancellable,
                                                                             NULL);

        manager_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), "/org/gnome/Kiosk/InputSources/Manager");
        self->input_sources_manager = kiosk_object_get_input_sources_manager (KIOSK_OBJECT (manager_object));

        g_signal_connect_object (G_OBJECT (self->input_sources_manager),
                                 "notify::selected-input-source",
                                 G_CALLBACK (set_menu_label_from_selected_input_source),
                                 self,
                                 G_CONNECT_SWAPPED);
        g_signal_connect_object (G_OBJECT (self->input_sources_manager),
                                 "notify::input-sources",
                                 G_CALLBACK (populate_input_sources_menu_with_input_source_manager),
                                 self,
                                 G_CONNECT_SWAPPED);
}

static void
activate (KioskInputSelectorApplication *self)
{
        g_debug ("KioskInputSelectorApplication: Activating");

        gtk_application_add_window (GTK_APPLICATION (self),
                                    GTK_WINDOW (self->window));

        create_switch_input_source_action (self);
        connect_to_input_source_manager (self);

        synchronize_input_sources_menu_with_input_source_manager (self);
}

static void
kiosk_input_selector_application_activate (GApplication *application)
{
        KioskInputSelectorApplication *self = KIOSK_INPUT_SELECTOR_APPLICATION (application);

        activate (self);

        G_APPLICATION_CLASS (kiosk_input_selector_application_parent_class)->activate (application);
}

static int
kiosk_input_selector_application_command_line (GApplication            *application,
                                               GApplicationCommandLine *command_line)
{
        KioskInputSelectorApplication *self = KIOSK_INPUT_SELECTOR_APPLICATION (application);

        GList *windows;
        GtkWidget *window;

        g_debug ("KioskInputSelectorApplication: Processing command line");
        G_APPLICATION_CLASS (kiosk_input_selector_application_parent_class)->command_line (application, command_line);
        activate (self);

        windows = gtk_application_get_windows (GTK_APPLICATION (self));
        window = GTK_WIDGET (g_list_first (windows)->data);

        gtk_widget_set_visible (GTK_WIDGET (window), TRUE);

        return 0;
}

static void
kiosk_input_selector_application_startup (GApplication *application)
{
        KioskInputSelectorApplication *self = KIOSK_INPUT_SELECTOR_APPLICATION (application);

        g_autoptr (GtkBuilder) builder = NULL;

        g_debug ("KioskInputSelectorApplication: Startup");

        G_APPLICATION_CLASS (kiosk_input_selector_application_parent_class)->startup (application);

        builder = gtk_builder_new_from_resource ("/ui/kiosk-input-selector-application.ui");

        g_set_weak_pointer (&self->window, GTK_WIDGET (gtk_builder_get_object (builder, "window")));
        g_set_weak_pointer (&self->input_sources_menu_button,
                            GTK_WIDGET (gtk_builder_get_object (builder, "input-sources-menu-button")));
        g_set_weak_pointer (&self->input_sources_menu,
                            G_MENU (gtk_builder_get_object (builder, "input-sources-menu")));
}

static void
kiosk_input_selector_application_init (KioskInputSelectorApplication *application)
{
        KioskInputSelectorApplication *self = KIOSK_INPUT_SELECTOR_APPLICATION (application);

        g_debug ("KioskInputSelectorApplication: Initializing");
        self->cancellable = g_cancellable_new ();
}

static void
kiosk_input_selector_application_dispose (GObject *object)
{
        KioskInputSelectorApplication *self = KIOSK_INPUT_SELECTOR_APPLICATION (object);

        if (self->cancellable != NULL) {
                g_cancellable_cancel (self->cancellable);
                g_clear_object (&self->cancellable);
        }

        g_clear_weak_pointer (&self->window);
        g_clear_weak_pointer (&self->input_sources_menu_button);
        g_clear_weak_pointer (&self->input_sources_menu);

        g_clear_object (&self->object_manager);
        g_clear_object (&self->input_sources_manager);
        G_OBJECT_CLASS (kiosk_input_selector_application_parent_class)->dispose (object);
}

static void
kiosk_input_selector_application_class_init (KioskInputSelectorApplicationClass *input_selector_application_class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (input_selector_application_class);
        GApplicationClass *application_class = G_APPLICATION_CLASS (input_selector_application_class);

        object_class->dispose = kiosk_input_selector_application_dispose;

        application_class->activate = kiosk_input_selector_application_activate;
        application_class->command_line = kiosk_input_selector_application_command_line;
        application_class->startup = kiosk_input_selector_application_startup;
}
07070100000035000081A40000000000000000000000016506F4B7000001B9000000000000000000000000000000000000004300000000gnome-kiosk-45.0/input-selector/kiosk-input-selector-application.h#pragma once

#include <glib-object.h>
#include <gtk/gtk.h>

G_BEGIN_DECLS
#define KIOSK_TYPE_INPUT_SELECTOR_APPLICATION (kiosk_input_selector_application_get_type ())

G_DECLARE_FINAL_TYPE (KioskInputSelectorApplication, kiosk_input_selector_application,
                      KIOSK, INPUT_SELECTOR_APPLICATION,
                      GtkApplication)

KioskInputSelectorApplication *kiosk_input_selector_application_new (void);

G_END_DECLS
07070100000036000081A40000000000000000000000016506F4B700000320000000000000000000000000000000000000004400000000gnome-kiosk-45.0/input-selector/kiosk-input-selector-application.ui<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <menu id="input-sources-menu">
  </menu>
  <object class="GtkBox" id="blank-title">
  </object>
  <object class="GtkApplicationWindow" id="window">
    <property name="default-width">1</property>
    <property name="default-height">1</property>
    <property name="resizable">false</property>
    <child type="titlebar">
      <object class="GtkHeaderBar" id="headerbar">
        <property name="title-widget">blank-title</property>
        <child type="end">
          <object class="GtkMenuButton" id="input-sources-menu-button">
            <property name="valign">center</property>
            <property name="menu-model">input-sources-menu</property>
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>
07070100000037000081A40000000000000000000000016506F4B7000000E6000000000000000000000000000000000000004300000000gnome-kiosk-45.0/input-selector/kiosk-input-selector.gresource.xml<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/">
  </gresource>
  <gresource prefix="/ui">
    <file preprocess="xml-stripblanks">kiosk-input-selector-application.ui</file>
  </gresource>
</gresources>
07070100000038000081A40000000000000000000000016506F4B70000017E000000000000000000000000000000000000002700000000gnome-kiosk-45.0/input-selector/main.c#include <stdlib.h>
#include <string.h>

#include <glib/gi18n.h>

#include "kiosk-input-selector-application.h"

int
main (int    argc,
      char **argv)
{
        g_autoptr (KioskInputSelectorApplication) application = NULL;

        application = kiosk_input_selector_application_new ();

        g_application_run (G_APPLICATION (application), argc, argv);

        return 0;
}
07070100000039000081A40000000000000000000000016506F4B700000568000000000000000000000000000000000000002C00000000gnome-kiosk-45.0/input-selector/meson.buildinput_selector_dependencies = []
input_selector_dependencies += dependency('gio-2.0')
input_selector_dependencies += dependency('glib-2.0')
input_selector_dependencies += dependency('gobject-2.0')
input_selector_dependencies += dependency('gtk4')

input_selector_sources = []
input_selector_sources += 'kiosk-input-selector-application.c'
input_selector_sources += 'main.c'

dbus_interface = 'org.gnome.Kiosk'
dbus_interface_file = join_paths('../dbus-interfaces', dbus_interface + '.xml')
sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
        namespace: 'Kiosk',
        interface_prefix: 'org.gnome.Kiosk',
        object_manager: true,
        annotations: [
                [ dbus_interface, 'org.gtk.GDBus.C.Name', 'Service' ],
                [ dbus_interface + '.InputSources', 'org.gtk.GDBus.C.Name', 'InputSourcesManager' ],
                [ dbus_interface + '.InputSources.InputSource', 'org.gtk.GDBus.C.Name', 'InputSource' ],
        ]
)

input_selector_sources += sources

resources = gnome.compile_resources('kiosk-input-selector-resources',
                                    'kiosk-input-selector.gresource.xml',
                                    source_dir: '.')
input_selector_sources += resources

executable('gnome-kiosk-input-selector', input_selector_sources,
        dependencies: input_selector_dependencies,
        install: false
)

0707010000003A000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001E00000000gnome-kiosk-45.0/kiosk-script0707010000003B000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002600000000gnome-kiosk-45.0/kiosk-script/desktop0707010000003C000081A40000000000000000000000016506F4B70000006B000000000000000000000000000000000000004B00000000gnome-kiosk-45.0/kiosk-script/desktop/org.gnome.Kiosk.Script.desktop.in.in[Desktop Entry]
Name=Kiosk Script
Type=Application
Exec=gnome-kiosk-script
X-GNOME-HiddenUnderSystemd=true
0707010000003D000081ED0000000000000000000000016506F4B7000002A6000000000000000000000000000000000000003100000000gnome-kiosk-45.0/kiosk-script/gnome-kiosk-script#!/usr/bin/sh

if [ ! -e ~/.local/bin/gnome-kiosk-script ]; then
    mkdir -p ~/.local/bin ~/.config
    cat > ~/.local/bin/gnome-kiosk-script <<- "EOF"
	#!/bin/sh
	# This script is located in ~/.local/bin.
	# It's provided as an example script to show how
	# the kiosk session works.  At the moment, the script
	# just starts a text editor open to itself, but it
	# should get customized to instead start a full screen
	# application designed for the kiosk deployment.
	gedit ~/.local/bin/gnome-kiosk-script

	sleep 1.0
	exec "$0" "$@"
EOF

    chmod +x ~/.local/bin/gnome-kiosk-script
    touch ~/.config/gnome-initial-setup-done
fi

exec ~/.local/bin/gnome-kiosk-script "$@"
0707010000003E000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002C00000000gnome-kiosk-45.0/kiosk-script/gnome-session0707010000003F000081A40000000000000000000000016506F4B700000056000000000000000000000000000000000000004700000000gnome-kiosk-45.0/kiosk-script/gnome-session/gnome-kiosk-script.session[GNOME Session]
Name=Kiosk
RequiredComponents=org.gnome.Kiosk;org.gnome.Kiosk.Script;
07070100000040000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002600000000gnome-kiosk-45.0/kiosk-script/systemd07070100000041000081A40000000000000000000000016506F4B700000098000000000000000000000000000000000000004800000000gnome-kiosk-45.0/kiosk-script/systemd/org.gnome.Kiosk.Script.service.in[Unit]
Description=Kiosk script
BindsTo=gnome-session.target
After=gnome-session.target

[Service]
ExecStart=@bindir@/gnome-kiosk-script
Restart=always
07070100000042000081A40000000000000000000000016506F4B70000004F000000000000000000000000000000000000003300000000gnome-kiosk-45.0/kiosk-script/systemd/session.conf[Unit]
Requires=org.gnome.Kiosk.target
Requires=org.gnome.Kiosk.Script.service
07070100000043000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002F00000000gnome-kiosk-45.0/kiosk-script/wayland-sessions07070100000044000081A40000000000000000000000016506F4B700000131000000000000000000000000000000000000005500000000gnome-kiosk-45.0/kiosk-script/wayland-sessions/gnome-kiosk-script-wayland.desktop.in[Desktop Entry]
Name=Kiosk Script Session (Wayland Display Server)
Comment=This session logs you into the sessoin started by ~/.local/bin/gnome-kiosk-script
Exec=gnome-session --session gnome-kiosk-script
TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Kiosk;GNOME;
X-GDM-SessionRegisters=true

07070100000045000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000002800000000gnome-kiosk-45.0/kiosk-script/xsessions07070100000046000081A40000000000000000000000016506F4B70000012D000000000000000000000000000000000000004B00000000gnome-kiosk-45.0/kiosk-script/xsessions/gnome-kiosk-script-xorg.desktop.in[Desktop Entry]
Name=Kiosk Script Session (X11 Display Server)
Comment=This session logs you into the sessoin started by ~/.local/bin/gnome-kiosk-script
Exec=gnome-session --session gnome-kiosk-script
TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Kiosk;GNOME;
X-GDM-SessionRegisters=true

07070100000047000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001700000000gnome-kiosk-45.0/meson07070100000048000081A40000000000000000000000016506F4B7000028AB000000000000000000000000000000000000001D00000000gnome-kiosk-45.0/meson.buildproject('gnome-kiosk', 'c',
        version: '45.0'
)
add_project_arguments('-D_GNU_SOURCE',
        language: 'c'
)

c_compiler = meson.get_compiler('c')

gnome = import('gnome')
i18n = import('i18n')

prefix = get_option('prefix')
datadir = join_paths(prefix, get_option('datadir'))
bindir = join_paths(prefix, get_option('bindir'))
localedir = join_paths(datadir, 'locale')
desktop_data_dir = join_paths(datadir, 'applications')
session_dir = join_paths(datadir, 'gnome-session', 'sessions')
xsessions_dir = join_paths(datadir, 'xsessions')
wayland_sessions_dir = join_paths(datadir, 'wayland-sessions')

po_dir = join_paths(meson.current_source_dir(), 'po')

config_data = configuration_data()
config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name())
config_data.set_quoted('VERSION', meson.project_version())
config_data.set_quoted('LOCALEDIR', localedir)

config_h = configure_file(
        input: 'config.h.meson',
        output: 'config.h',
        configuration: config_data
)

meson.add_install_script ('meson/postinstall.py')

mutter_api_version = 13
libmutter_name = 'libmutter-@0@'.format(mutter_api_version)
libmutter_cogl_name = 'mutter-cogl-@0@'.format(mutter_api_version)
libmutter_cogl_pango_name = 'mutter-cogl-pango-@0@'.format(mutter_api_version)
libmutter_clutter_name = 'mutter-clutter-@0@'.format(mutter_api_version)

mutter_dependency = dependency(libmutter_name)
mutter_libdir = mutter_dependency.get_pkgconfig_variable('typelibdir')

systemd_user_unit_dir = dependency('systemd').get_pkgconfig_variable('systemduserunitdir',
                                                                     define_variable: ['prefix', prefix])
systemd_dependency = dependency('libsystemd')

dbus_proxies = []
dbus_proxies += {
        'prefix':   'org.gnome.DisplayManager',
        'namespace': 'Gdm',
        'interface': 'Manager',
}

dbus_proxies += {
        'prefix':   'org.freedesktop',
        'namespace': 'Sd',
        'interface': 'locale1',
}

dbus_proxies += {
        'prefix':   'org.gnome',
        'namespace': 'Gsm',
        'interface': 'SessionManager',
}

dbus_interface_sources_map = {}
foreach dbus_proxy : dbus_proxies
        dbus_interface = dbus_proxy['prefix'] + '.' + dbus_proxy['interface']
        dbus_interface_file = join_paths('dbus-interfaces', dbus_interface + '.xml')
        sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
                namespace: dbus_proxy['namespace'],
                interface_prefix: dbus_proxy['prefix'],
        )
        dbus_interface_sources_map += { dbus_interface: sources }
endforeach

dbus_interface = 'org.gnome.Kiosk'
dbus_interface_file = join_paths('dbus-interfaces', dbus_interface + '.xml')
sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
        namespace: 'KioskDBus',
        interface_prefix: 'org.gnome.Kiosk',
        object_manager: true,
        annotations: [
                [ dbus_interface, 'org.gtk.GDBus.C.Name', 'Service' ],
                [ dbus_interface + '.InputSources', 'org.gtk.GDBus.C.Name', 'InputSourcesManager' ],
                [ dbus_interface + '.InputSources.InputSource', 'org.gtk.GDBus.C.Name', 'InputSource' ],
        ]
)
dbus_interface_sources_map += { dbus_interface: sources }

dbus_interface = 'org.gnome.Shell'
dbus_interface_file = join_paths('dbus-interfaces', dbus_interface + '.xml')
sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
        namespace: 'Kiosk',
        interface_prefix: 'org.gnome',
        annotations: [
                [ dbus_interface, 'org.gtk.GDBus.C.Name', 'ShellDBusService' ]
        ]
)
dbus_interface_sources_map += { dbus_interface: sources }

compositor_dependencies = []
compositor_dependencies += c_compiler.find_library('m')
compositor_dependencies += dependency('gio-2.0')
compositor_dependencies += dependency('glib-2.0')
compositor_dependencies += dependency('gnome-desktop-4')
compositor_dependencies += dependency('gobject-2.0')
compositor_dependencies += dependency('ibus-1.0')
compositor_dependencies += dependency(libmutter_cogl_name)
compositor_dependencies += dependency(libmutter_cogl_pango_name)
compositor_dependencies += dependency(libmutter_clutter_name)
compositor_dependencies += mutter_dependency
compositor_dependencies += systemd_dependency

compositor_sources = []
compositor_sources += 'compositor/kiosk-backgrounds.c'
compositor_sources += 'compositor/kiosk-compositor.c'
compositor_sources += 'compositor/kiosk-dbus-utils.c'
compositor_sources += 'compositor/kiosk-gobject-utils.c'
compositor_sources += 'compositor/kiosk-input-sources-manager.c'
compositor_sources += 'compositor/kiosk-input-engine-manager.c'
compositor_sources += 'compositor/kiosk-input-source-group.c'
compositor_sources += 'compositor/kiosk-service.c'
compositor_sources += 'compositor/kiosk-shell-service.c'
compositor_sources += 'compositor/kiosk-x-keyboard-manager.c'
compositor_sources += 'compositor/main.c'

foreach dbus_interface, sources: dbus_interface_sources_map
        compositor_sources += sources
endforeach

executable('gnome-kiosk', compositor_sources,
        dependencies: compositor_dependencies,
        build_rpath: mutter_libdir,
        install_rpath: mutter_libdir,
        install: true
)

desktop_config_data = configuration_data()
desktop_config_data.set('bindir', bindir)

desktop_file = configure_file(
        input: 'compositor/data/org.gnome.Kiosk.desktop.in.in',
        output: 'org.gnome.Kiosk.desktop.in',
        configuration: desktop_config_data
)

i18n.merge_file(
        input: desktop_file,
        output: 'org.gnome.Kiosk.desktop',
        po_dir: po_dir,
        install: true,
        install_dir: desktop_data_dir,
        type: 'desktop'
)

systemd_service_config_data = configuration_data()
systemd_service_config_data.set('bindir', bindir)

systemd_service_files = []
systemd_service_files += 'compositor/data/systemd/org.gnome.Kiosk@wayland.service.in'
systemd_service_files += 'compositor/data/systemd/org.gnome.Kiosk@x11.service.in'

foreach service_file : systemd_service_files
        configure_file(
                input: service_file,
                output: '@BASENAME@',
                configuration: systemd_service_config_data,
                install_dir: systemd_user_unit_dir
        )
endforeach

install_data(
        'compositor/data/systemd/org.gnome.Kiosk.target',
        install_dir: systemd_user_unit_dir
)

systemd_service_config_data = configuration_data()
systemd_service_config_data.set('bindir', bindir)

dconf_config_data = configuration_data()
dconf_config_data.set('PACKAGE', meson.project_name())
dconf_config_data.set('DATADIR', datadir)

dconf_profile_dir = join_paths(datadir, 'dconf/profile')
dconf = configure_file(
        input: 'compositor/data/dconf/gnomekiosk.in',
        output: '@BASENAME@.configured',
        configuration: dconf_config_data,
)
install_data(dconf,
        install_dir: dconf_profile_dir,
        rename: 'gnomekiosk'
)

dconf_dir = join_paths(datadir, meson.project_name())
dconf_defaults_input_dir = join_paths (meson.current_source_dir(), 'compositor/data/dconf/defaults')
dconf_defaults = custom_target('gnomekiosk.dconf.compiled',
        output: 'gnomekiosk.dconf.compiled',
        input:  'compositor/data/dconf/defaults/gnomekiosk.dconf',
        command: [
                find_program('dconf'),
                'compile',
                '@OUTPUT@',
                dconf_defaults_input_dir
        ],
        install: true,
        install_dir: dconf_dir
)

install_data('kiosk-script/gnome-kiosk-script',
        install_dir: bindir,
	install_mode: 'rwxr-xr-x'
)

desktop_file = configure_file(
        input: 'kiosk-script/desktop/org.gnome.Kiosk.Script.desktop.in.in',
        output: 'org.gnome.Kiosk.Script.desktop.in',
        configuration: desktop_config_data
)

i18n.merge_file(
        input: desktop_file,
        output: 'org.gnome.Kiosk.Script.desktop',
        po_dir: po_dir,
        install: true,
        install_dir: desktop_data_dir,
        type: 'desktop'
)

configure_file(
       input: 'kiosk-script/systemd/org.gnome.Kiosk.Script.service.in',
       output: '@BASENAME@',
       configuration: systemd_service_config_data,
       install_dir: systemd_user_unit_dir
)

kiosk_script_systemd_target_dir = join_paths(systemd_user_unit_dir, 'gnome-session@gnome-kiosk-script.target.d')
install_data('kiosk-script/systemd/session.conf',
        install_dir: kiosk_script_systemd_target_dir
)

install_data('kiosk-script/gnome-session/gnome-kiosk-script.session',
        install_dir: session_dir,
)

i18n.merge_file(
        input: 'kiosk-script/xsessions/gnome-kiosk-script-xorg.desktop.in',
        output: '@BASENAME@',
        po_dir: po_dir,
        install: true,
        install_dir: xsessions_dir,
        type: 'desktop'
)

i18n.merge_file(
        input: 'kiosk-script/wayland-sessions/gnome-kiosk-script-wayland.desktop.in',
        output: '@BASENAME@',
        po_dir: po_dir,
        install: true,
        install_dir: wayland_sessions_dir,
        type: 'desktop'
)

session_config_data = configuration_data()
session_config_data.set('required_components', 'org.gnome.Kiosk;org.gnome.Kiosk.SearchApp;')

session_file = configure_file(
        input: 'search-app/org.gnome.Kiosk.SearchApp.session.desktop.in.in',
        output: 'org.gnome.Kiosk.SearchApp.session.desktop.in',
        configuration: session_config_data
)

subdir('input-selector')

i18n.merge_file(
        input: session_file,
        output: 'org.gnome.Kiosk.SearchApp.session',
        po_dir: po_dir,
        install: true,
        install_dir: session_dir,
        type: 'desktop'
)

i18n.merge_file(
        input: 'search-app/org.gnome.Kiosk.SearchApp.Session.desktop.in',
        output: 'org.gnome.Kiosk.SearchApp.Session.desktop',
        po_dir: po_dir,
        install: true,
        install_dir: xsessions_dir,
        type: 'desktop'
)

search_app_desktop_file = configure_file(
        input: 'search-app/org.gnome.Kiosk.SearchApp.desktop.in.in',
        output: 'org.gnome.Kiosk.SearchApp.desktop.in',
        configuration: desktop_config_data
)

i18n.merge_file(
        input: search_app_desktop_file,
        output: 'org.gnome.Kiosk.SearchApp.desktop',
        po_dir: po_dir,
        install: true,
        install_dir: desktop_data_dir,
        type: 'desktop'
)

test('check-format', find_program('scripts/check-format.sh'))

07070100000049000081ED0000000000000000000000016506F4B7000005CB000000000000000000000000000000000000002600000000gnome-kiosk-45.0/meson/postinstall.py#!/usr/bin/env python3

import os
import shutil
import subprocess
import sys

destdir = os.environ.get('DESTDIR', '/')
prefix = os.environ.get('MESON_INSTALL_PREFIX', '/usr/local')
datadir = os.path.join(destdir + prefix, 'share')

wayland_sessions_dir = os.path.join(datadir, 'wayland-sessions')
if not os.path.exists(wayland_sessions_dir):
    os.makedirs(wayland_sessions_dir)

source_file = os.path.join(datadir, 'xsessions', 'org.gnome.Kiosk.SearchApp.Session.desktop')
destination_file = os.path.join(wayland_sessions_dir, 'org.gnome.Kiosk.SearchApp.Session.desktop')
shutil.copyfile(source_file, destination_file)

# Packaging tools define DESTDIR and this isn't needed for them
if 'DESTDIR' not in os.environ:
    print('Updating icon cache...')
    icon_cache_dir = os.path.join(datadir, 'icons', 'hicolor')
    if not os.path.exists(icon_cache_dir):
        os.makedirs(icon_cache_dir)
    subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir])

    print('Updating desktop database...')
    desktop_database_dir = os.path.join(datadir, 'applications')
    if not os.path.exists(desktop_database_dir):
        os.makedirs(desktop_database_dir)
    subprocess.call(['update-desktop-database', '-q', desktop_database_dir])

    print('Compiling GSettings schemas...')
    schemas_dir = os.path.join(datadir, 'glib-2.0', 'schemas')
    if not os.path.exists(schemas_dir):
        os.makedirs(schemas_dir)
    subprocess.call(['glib-compile-schemas', schemas_dir])
0707010000004A000081A40000000000000000000000016506F4B700000000000000000000000000000000000000000000002300000000gnome-kiosk-45.0/meson_options.txt0707010000004B000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001400000000gnome-kiosk-45.0/po0707010000004C000081A40000000000000000000000016506F4B700000000000000000000000000000000000000000000001C00000000gnome-kiosk-45.0/po/LINGUAS0707010000004D000081A40000000000000000000000016506F4B700000000000000000000000000000000000000000000002000000000gnome-kiosk-45.0/po/POTFILES.in0707010000004E000081A40000000000000000000000016506F4B700000000000000000000000000000000000000000000002200000000gnome-kiosk-45.0/po/POTFILES.skip0707010000004F000081A40000000000000000000000016506F4B700000033000000000000000000000000000000000000002000000000gnome-kiosk-45.0/po/meson.buildi18n.gettext(meson.project_name(), preset: 'glib')
07070100000050000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001900000000gnome-kiosk-45.0/scripts07070100000051000081ED0000000000000000000000016506F4B7000004D1000000000000000000000000000000000000002900000000gnome-kiosk-45.0/scripts/check-format.sh#!/bin/sh

SRC_DIR=$(dirname "$0")/..

exec >& /dev/stderr

set -x
env

if [ -z "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]; then
    UPSTREAM_BRANCH="$(git rev-parse --abbrev-ref --symbolic-full-name @{u})"
else
    UPSTREAM_BRANCH="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
fi

cd "$SRC_DIR"

cp scripts/uncrustify.cfg scripts/latest-uncrustify.cfg

git diff --quiet
DIRTY_TREE="$?"

if [ "$DIRTY_TREE" -ne 0 ]; then
    git stash
    git stash apply
fi

git ls-files '*.[ch]' | while read file; do
    uncrustify -q -c scripts/latest-uncrustify.cfg --replace "${file}" \;
done

echo > after
git ls-files '*.[ch]' | while read file; do
    git diff -- "${file}" \; >> after
done

git reset --hard $UPSTREAM_BRANCH
git ls-files '*.[ch]' | while read file; do
    uncrustify -q -c scripts/latest-uncrustify.cfg --replace "${file}" \;
done

echo > before
git ls-files '*.[ch]' | while read file; do
    git diff -- "${file}" \; >> before
done

interdiff --no-revert-omitted before after > diff

if [ -n "$(cat diff)" ]; then
    echo "Uncrustify found style abnormalities" 2>&1
    cat diff
    exit 1
fi

git reset --hard HEAD@{1}

if [ "$DIRTY_TREE" -ne 0 ]; then
    git stash pop
fi

echo "No new style abnormalities found by uncrustify!"
exit 0

07070100000052000081ED0000000000000000000000016506F4B700000782000000000000000000000000000000000000003A00000000gnome-kiosk-45.0/scripts/generate-dbus-proxy-interface.sh#!/bin/sh

if [ ! -e "dbus-interfaces/" ]; then
        echo "Please run from top level source directory" > /dev/stderr
        exit 1
fi

export LANG="C.utf-8"

SERVICE="$1"
INTERFACE="${2:-$1}"
OBJECT_PATH="${3:-/$(echo -n ${INTERFACE} | sed 's![.]!/!g')}"
OUTPUT_FILE="dbus-interfaces/${INTERFACE}.xml"

# The sed goo here:
# 1. unescapes new lines and smashes them into a single non-delimiting character
# 2. unescapes anything else (mainly quote marks)
# 3. strips off the s "..." around the result
# 4. smashes </interface> into a single character, so we can do a non-greedy
#    match for it.
# 5. smashes the interface into a single character, so we can do a non-greedy
#    match for it
# 6. do the aforementioned matches to erase all interfaces from output we
#    weren't asked for
# 7. restore </interface> and the interface to their true selves
# 8. likewise, put the new lines back in the stream
busctl call "${SERVICE}" "${OBJECT_PATH}"                                      \
            org.freedesktop.DBus.Introspectable Introspect                     \
       | sed -e 's!\\n!\r!g'                                                   \
             -e 's!\\\(.\)!\1!g'                                               \
             -e 's!s "\(.*\)"$!\1!'                                            \
             -e 's!'${INTERFACE}'!␚!g'                                         \
             -e 's!</interface>!␙!g'                                           \
             -e 's!<interface name="[^␚]*">[^␙]*␙!!g'                          \
             -e 's!␙!</interface>!g'                                           \
             -e 's!␚!'${INTERFACE}'!g'                                         \
             -e 's!\r[\r ]*\r!\r!g'                                            \
             -e 's!\r!\n!g'                                                    \
       > "${OUTPUT_FILE}"
07070100000053000081A40000000000000000000000016506F4B700000E13000000000000000000000000000000000000002800000000gnome-kiosk-45.0/scripts/uncrustify.cfgindent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs
input_tab_size = 8 # original tab size
output_tab_size = 8 # new tab size
indent_columns = output_tab_size

indent_label = 1 # pos: absolute col, neg: relative column


#
# inter-symbol newlines
#

nl_enum_brace = force # "enum {" vs "enum \n {"
nl_union_brace = force # "union {" vs "union \n {"
nl_struct_brace = force # "struct {" vs "struct \n {"
nl_do_brace = remove # "do {" vs "do \n {"
nl_if_brace = remove # "if () {" vs "if () \n {"
nl_for_brace = remove # "for () {" vs "for () \n {"
nl_else_brace = remove # "else {" vs "else \n {"
nl_while_brace = remove # "while () {" vs "while () \n {"
nl_switch_brace = remove # "switch () {" vs "switch () \n {"
nl_brace_while = remove # "} while" vs "} \n while" - cuddle while
nl_brace_else = remove # "} else" vs "} \n else" - cuddle else
sp_brace_else = force
sp_else_brace = force
nl_func_def_args = add
nl_func_var_def_blk = 0
nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{"
nl_fdef_brace = add # "int foo() {" vs "int foo()\n{"
# nl_after_return = TRUE;
# nl_before_case = 1


#
# Source code modifications
#

mod_paren_on_return = remove # "return 1;" vs "return (1);"
mod_full_brace_if = ignore # "if (a) a--;" vs "if (a) { a--; }"
mod_full_brace_if_chain = 3
mod_full_brace_for = force # "for () a--;" vs "for () { a--; }"
mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();"
mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }"
mod_full_brace_nl = 3 # don't remove if more than 3 newlines
mod_remove_extra_semicolon = true


#
# inter-character spacing options
#

sp_return_paren = force # "return (1);" vs "return(1);"
sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
sp_before_sparen = force # "if (" vs "if("
sp_after_sparen = force # "if () {" vs "if (){"
sp_after_cast = force # "(int) a" vs "(int)a"
sp_inside_braces = force # "{ 1 }" vs "{1}"
sp_inside_braces_struct = force # "{ 1 }" vs "{1}"
sp_inside_braces_enum = force # "{ 1 }" vs "{1}"
sp_assign = force
sp_arith = force
sp_bool = force
sp_compare = force
sp_assign = force
sp_after_comma = force
sp_func_def_paren = force # "int foo (){" vs "int foo(){"
sp_func_call_paren = force # "foo (" vs "foo("
sp_func_proto_paren = force # "int foo ();" vs "int foo();"


#
# Aligning stuff
#

align_with_tabs = FALSE # use tabs to align
align_on_tabstop = FALSE # align on tabstops
align_var_def_gap = 1
align_func_proto_gap = 4
align_var_def_thresh = 0
# align_keep_tabs = true
align_enum_equ_span = 4 # '=' in enum definition
# align_nl_cont = TRUE
# align_var_def_span = 2
# align_var_def_inline = TRUE
# align_var_def_colon = TRUE
# align_assign_span = 1
align_struct_init_span = 3 # align stuff in a structure init '= { }'
align_right_cmt_span = 3
# align_pp_define_span = 8;
# align_pp_define_gap = 4;
align_func_params_gap = 2
align_func_params_span = 10

cmt_star_cont = true

# indent_brace = 0

nl_func_paren = remove
nl_func_decl_start = remove
nl_func_decl_empty = remove
nl_func_decl_args = force
nl_func_decl_end = remove
sp_inside_paren = remove
sp_inside_square = remove
sp_inside_paren_cast = remove
sp_inside_fparen = remove
sp_inside_sparen = remove
sp_paren_paren = remove
sp_before_ptr_star = force
sp_after_ptr_star = remove
sp_between_ptr_star = remove
align_func_params = true
align_var_struct_span = 6

eat_blanks_after_open_brace = true
eat_blanks_before_close_brace = true
pp_indent = remove

nl_start_of_file = remove
nl_end_of_file = force
nl_end_of_file_min = 1
nl_comment_func_def = 1
align_var_def_star_style = 2
07070100000054000041ED0000000000000000000000026506F4B700000000000000000000000000000000000000000000001C00000000gnome-kiosk-45.0/search-app07070100000055000081A40000000000000000000000016506F4B7000000FE000000000000000000000000000000000000004900000000gnome-kiosk-45.0/search-app/org.gnome.Kiosk.SearchApp.Session.desktop.in[Desktop Entry]
Name=Search Appliance Session
Comment=This session logs you into a search appliance
Exec=gnome-session --session org.gnome.Kiosk.SearchApp
TryExec=gnome-session
Type=Application
DesktopNames=GNOME-Kiosk;GNOME;
X-GDM-SessionRegisters=true
07070100000056000081A40000000000000000000000016506F4B70000011E000000000000000000000000000000000000004400000000gnome-kiosk-45.0/search-app/org.gnome.Kiosk.SearchApp.desktop.in.in[Desktop Entry]
Type=Application
Name=Search Appliance
Comment=Sample Search Appliance Application for GNOME Kiosk
Exec=@bindir@/firefox --kiosk --private-window --new-instance  https://www.google.com
Categories=GNOME;GTK;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-AutoRestart=true
07070100000057000081A40000000000000000000000016506F4B70000004F000000000000000000000000000000000000004C00000000gnome-kiosk-45.0/search-app/org.gnome.Kiosk.SearchApp.session.desktop.in.in[GNOME Session]
Name=Search Appliance
RequiredComponents=@required_components@
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!613 blocks
openSUSE Build Service is sponsored by