This file is indexed.

/usr/share/pyshared/synaptiks/config.py is in kde-config-touchpad 0.8.1-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# -*- coding: utf-8 -*-
# Copyright (c) 2010, 2011, 2012, Sebastian Wiesner <lunaryorn@googlemail.com>
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:

# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.


"""
    synaptiks.config
    ================

    Configuration classes
    ---------------------

    This module provides the configuration classes for the touchpad and the
    touchpad manager.  These configuration classes are simply mappings, which
    expose the *current* state of the associated objects (and *not* the state
    of the configuration on disk).  This allows the user to configure the live
    state of these objects, which is especially important for touchpad
    configuration, which can be changed from outside of |synaptiks| using
    utilities like :program:`xinput`.

    To save the configuration permanently, these mappings, and consequently the
    current configuration state of the associated objects, is simply dumped in
    JSON format to the configuration directory (see
    :func:`get_configuration_directory()`).

    To apply a dumped configuration, it is loaded as standard dict from the
    JSON dump, and then the corresponding configuration mapping is updated with
    this dict.  All configuration mappings provide a convenient
    :meth:`~TouchpadConfiguration.load()` method to create a new configuration
    mapping updated with the dumped configuration.

    Handling of default values
    --------------------------

    Configuration mappings provided by this module provide their default values
    through a ``defaults`` property, see :attr:`TouchpadConfiguration.defaults`
    and :attr:`ManagerConfiguration.defaults`.

    In case of :class:`ManagerConfiguration` these are explicit default values,
    which do not change.  :class:`TouchpadConfiguration` however uses the
    defaults provided by the touchpad driver.

    Unfortunately the touchpad driver does not provide special access to these
    default values.  To work around this restriction, |synaptiks| saves the
    touchpad configuration to disc (see
    :func:`get_touchpad_defaults_file_path()`) right after session startup
    (through an autostart command ``synaptikscfg init``, see
    :ref:`script_usage`), before loading the actual configuration.  At this
    point, the driver properties haven't yet been modified, and thus still
    contain the default values.  These dumped defaults can later be loaded
    through :func:`get_touchpad_defaults()` and are also returned by
    :attr:`TouchpadConfiguration.defaults`.

    .. _script_usage:

    Script usage
    ------------

    .. program:: synaptikscfg

    This module is usable as script, available also as :program:`synaptikscfg`
    in the ``$PATH``.  It provides three different actions, of which ``load``
    and ``save`` are really self-explanatory. ``init`` however deserves some
    detailled explanation.

    The `init` action is supposed to run automatically as script during session
    startup.  To do this, the installation script installs an autostart entry
    (as specified by the `XDG Desktop Application Autostart Specification`_) to
    execute ``synaptikscfg init`` at session startup.  This action first dumps
    the default settings from the touchpad driver as described above, and then
    loads and applies the actual touchpad configuration stored on disk.

    The command line parsing of the script is implemented with :mod:`argparse`,
    so you can expected standard semantics, and an extensive ``--help`` option.

    .. _XDG Desktop Application Autostart Specification: http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html

    .. moduleauthor::  Sebastian Wiesner  <lunaryorn@googlemail.com>
"""

from __future__ import (print_function, division, unicode_literals,
                        absolute_import)

import os
from collections import MutableMapping

from synaptiks.util import ensure_directory, save_json, load_json


def get_configuration_directory():
    """
    Get the configuration directory of synaptiks according to the `XDG base
    directory specification`_ as string.  The directory is guaranteed to exist.

    The configuration directory is a sub-directory of ``$XDG_CONFIG_HOME``
    (which defaults to ``$HOME/.config``).

    Raise :exc:`~exceptions.EnvironmentError`, if the creation of the
    configuration directory fails.

    .. _`XDG base directory specification`: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
    """
    xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
    if not xdg_config_home:
        xdg_config_home = os.path.expandvars(os.path.join('$HOME', '.config'))
    return ensure_directory(os.path.join(xdg_config_home, 'synaptiks'))


def get_touchpad_config_file_path():
    """
    Get the path to the file which stores the touchpad configuration.
    """
    return os.path.join(get_configuration_directory(), 'touchpad-config.json')


def get_touchpad_defaults_file_path():
    """
    Get the path to the file which stores the default touchpad configuration as
    setup by the touchpad driver.
    """
    return os.path.join(get_configuration_directory(),
                        'touchpad-defaults.json')


def get_management_config_file_path():
    """
    Get the path to the file which stores the touchpad management
    configuration.
    """
    return os.path.join(get_configuration_directory(), 'management.json')


def get_touchpad_defaults(filename=None):
    """
    Get the default touchpad settings as :func:`dict` *without* applying it to
    the touchpad.
    """
    if not filename:
        filename = get_touchpad_defaults_file_path()
    return load_json(filename, default={})


class TouchpadConfiguration(MutableMapping):
    """
    A mutable mapping class representing the current configuration of the
    touchpad.

    As a special case, deleting a key (e.g. ``del config['minimum_speed']``)
    resets the setting back to its default value (as provided by
    :attr:`defaults`).
    """

    CONFIG_KEYS = frozenset([
        'minimum_speed', 'maximum_speed', 'acceleration_factor',
        'edge_motion_always', 'fast_taps',
        'rt_tap_action', 'rb_tap_action', 'lt_tap_action', 'lb_tap_action',
        'f1_tap_action', 'f2_tap_action', 'f3_tap_action',
        'tap_and_drag_gesture', 'locked_drags', 'locked_drags_timeout',
        'vertical_edge_scrolling', 'horizontal_edge_scrolling',
        'corner_coasting', 'coasting_speed',
        'vertical_scrolling_distance', 'horizontal_scrolling_distance',
        'vertical_two_finger_scrolling', 'horizontal_two_finger_scrolling',
        'circular_scrolling', 'circular_scrolling_trigger',
        'circular_scrolling_distance', 'circular_touchpad'])

    @classmethod
    def load(cls, touchpad, filename=None):
        """
        Load the configuration for the given ``touchpad`` from disc.

        If no ``filename`` is given, the configuration is loaded from the
        default configuration file as returned by
        :func:`get_touchpad_config_file_path`.  Otherwise the configuration is
        loaded from the given file.  If the file doesn't exist, an empty
        configuration is loaded.

        After the configuration is loaded, it is applied to the given
        ``touchpad``.

        ``touchpad`` is a :class:`~synaptiks.touchpad.Touchpad` object.
        ``filename`` is either ``None`` or a string containing the path to a
        file.

        Return a :class:`TouchpadConfiguration` object.  Raise
        :exc:`~exceptions.EnvironmentError`, if the file could not be loaded,
        but *not* in case of a non-existing file.
        """
        if not filename:
            filename = get_touchpad_config_file_path()
        config = cls(touchpad)
        config.update(load_json(filename, default={}))
        return config

    def __init__(self, touchpad):
        """
        Create a new configuration from the given ``touchpad``.

        ``touchpad`` is a :class:`~synaptiks.touchpad.Touchpad` object.
        """
        self.touchpad = touchpad

    @property
    def defaults(self):
        """
        A dictionary of default values for this configuration.

        The default values of this configuration are dynamically loaded from
        disc, where the have been dumped to at session startup.

        Use ``config.update(config.defaults)`` to restore the configuration to
        its default values.
        """
        return get_touchpad_defaults()

    def __contains__(self, key):
        return key in self.CONFIG_KEYS

    def __len__(self):
        return len(self.CONFIG_KEYS)

    def __iter__(self):
        return iter(self.CONFIG_KEYS)

    def __getitem__(self, key):
        if key not in self:
            raise KeyError(key)
        value = getattr(self.touchpad, key)
        if isinstance(value, float):
            # round floats for the sake of comparability and readability
            value = round(value, 5)
        return value

    def __setitem__(self, key, value):
        if key not in self:
            raise KeyError(key)
        setattr(self.touchpad, key, value)

    def __delitem__(self, key):
        default = self.defaults.get(key)
        if default is not None:
            self[key] = default

    def save(self, filename=None):
        """
        Save the configuration.

        If no ``filename`` is given, the configuration is saved to the default
        configuration file as returned by
        :func:`get_touchpad_config_file_path`.  Otherwise the configuration is
        saved to the given file.

        ``filename`` is either ``None`` or a string containing the path to a
        file.

        Raise :exc:`~exceptions.EnvironmentError`, if the file could not be
        written.
        """
        if not filename:
            filename = get_touchpad_config_file_path()
        save_json(filename, dict(self))


class ManagerConfiguration(MutableMapping):
    """
    A mutable mapping class representing the configuration of a
    :class:`~synaptiks.management.TouchpadManager`.

    As a special case, deleting a key (e.g. ``del config['minimum_speed']``)
    resets the setting back to its default value (as provided by
    :attr:`defaults`).
    """

    #: A mapping with the default values for all configuration keys
    _DEFAULTS = {'monitor_mouses': False, 'ignored_mouses': [],
                'monitor_keyboard': False, 'idle_time': 2.0,
                'keys_to_ignore': 2}

    #: config keys to be applied to the mouse_manager
    MOUSE_MANAGER_KEYS = frozenset(['ignored_mouses'])
    #: config keys to be applied to the keyboard monitor
    KEYBOARD_MONITOR_KEYS = frozenset(['idle_time', 'keys_to_ignore'])

    @classmethod
    def load(cls, touchpad_manager, filename=None):
        """
        Load the configuration for the given ``touchpad_manager`` from disc.

        If no ``filename`` is given, the configuration is loaded from the
        default configuration file as returned by
        :func:`get_management_config_file_path`.  Otherwise the configuration
        is loaded from the given file.  If the file doesn't exist, the default
        config as given by :attr:`defaults` is loaded.

        After the configuration is loaded, it is applied to the given
        ``touchpad_manager``.

        ``touchpad_manager`` is a
        :class:`~synaptiks.management.TouchpadManager` object.  ``filename`` is
        either ``None`` or a string containing the path to a file.

        Return a :class:`ManagerConfiguration` object.  Raise
        :exc:`~exceptions.EnvironmentError`, if the file could not be loaded,
        but *not* in case of a non-existing file.
        """
        if not filename:
            filename = get_management_config_file_path()
        config = cls(touchpad_manager)
        # use defaults for all non-existing settings
        loaded_config = dict(cls._DEFAULTS)
        loaded_config.update(load_json(filename, default={}))
        config.update(loaded_config)
        return config

    def __init__(self, touchpad_manager):
        self.touchpad_manager = touchpad_manager

    @property
    def defaults(self):
        """
        A dictionary of default values for this configuration.

        This dictionary is a copy, modifications do not affect future access to
        this attribute.  Consequently you are free to modify this dictionary as
        you like.

        Use ``config.update(config.defaults)`` to restore the configuration to
        its default values.
        """
        return dict(self._DEFAULTS)

    @property
    def mouse_manager(self):
        return self.touchpad_manager.mouse_manager

    @property
    def keyboard_monitor(self):
        return self.touchpad_manager.keyboard_monitor

    def __contains__(self, key):
        return key in self._DEFAULTS

    def __len__(self):
        return len(self._DEFAULTS)

    def __iter__(self):
        return iter(self._DEFAULTS)

    def __getitem__(self, key):
        if key not in self:
            raise KeyError(key)
        target = self.touchpad_manager
        if key in self.MOUSE_MANAGER_KEYS:
            target = self.mouse_manager
        elif key in self.KEYBOARD_MONITOR_KEYS:
            target = self.keyboard_monitor
        return getattr(target, key)

    def __setitem__(self, key, value):
        if key not in self:
            raise KeyError(key)
        target = self.touchpad_manager
        if key in self.MOUSE_MANAGER_KEYS:
            target = self.mouse_manager
        elif key in self.KEYBOARD_MONITOR_KEYS:
            target = self.keyboard_monitor
        setattr(target, key, value)

    def __delitem__(self, key):
        self[key] = self._DEFAULTS[key]

    def save(self, filename=None):
        """
        Save the configuration.

        If no ``filename`` is given, the configuration is saved to the default
        configuration file as returned by
        :func:`get_management_config_file_path`.  Otherwise the configuration
        is saved to the given file.

        ``filename`` is either ``None`` or a string containing the path to a
        file.

        Raise :exc:`~exceptions.EnvironmentError`, if the file could not be
        written.
        """
        if not filename:
            filename = get_management_config_file_path()
        save_json(filename, dict(self))


def main():
    from argparse import ArgumentParser

    from synaptiks import __version__
    from synaptiks.x11 import Display, DisplayError
    from synaptiks.touchpad import Touchpad, NoTouchpadError

    parser = ArgumentParser(
        description='synaptiks touchpad configuration utility',
        epilog="""\
Copyright (C) 2010 Sebastian Wiesner <lunaryorn@googlemail.com>,
distributed under the terms of the BSD License""")
    parser.add_argument('--version', help='Show synaptiks version',
                        action='version', version=__version__)
    actions = parser.add_subparsers(title='Actions')

    init_act = actions.add_parser(
        'init', help='Initialize touchpad configuration.  Should not be '
        'called manually, but automatically at session startup.')
    init_act.set_defaults(action='init')

    load_act = actions.add_parser(
        'load', help='Load the touchpad configuration')
    load_act.add_argument(
        'filename', nargs='?', help='File to load the configuration from.  If '
        'empty, the default configuration file is loaded.')
    load_act.set_defaults(action='load')

    save_act = actions.add_parser(
        'save', help='Save the current touchpad configuration')
    save_act.add_argument(
        'filename', nargs='?', help='File to save the configuration to.  If '
        'empty, the default configuration file is used.')
    save_act.set_defaults(action='save')

    # default filename to load configuration from
    parser.set_defaults(filename=None)

    # we don't have any arguments, but need to make sure, that the builtin
    # arguments (--help mainly) are handled
    args = parser.parse_args()

    try:
        with Display.from_name() as display:
            touchpad = Touchpad.find_first(display)

            if args.action == 'init':
                driver_defaults = TouchpadConfiguration(touchpad)
                driver_defaults.save(get_touchpad_defaults_file_path())
            if args.action in ('init', 'load'):
                TouchpadConfiguration.load(touchpad, filename=args.filename)
            if args.action == 'save':
                current_config = TouchpadConfiguration(touchpad)
                current_config.save(filename=args.filename)
    except DisplayError:
        parser.error('could not connect to X11 display')
    except NoTouchpadError:
        parser.error('no touchpad found')


if __name__ == '__main__':
    main()