332 Commits

Author SHA1 Message Date
Peter Hutterer
7036428066 meson.build: libratbag 0.9.900
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-25 13:48:39 +10:00
Peter Hutterer
18239f1aee DBusInterface: add missing 'Methods' header
And consistently use ':' after Properties/Methods headers

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-24 09:25:29 +10:00
Benjamin Tissoires
fe8fde79f6 tools: ratbagctl: fix len(array) > 0 check
"for python, instead of checking len > 0 we're supposed to use
if input_string"

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 09:28:07 +02:00
Peter Hutterer
9f805a4ebe tools: don't return a ratbagd_process if things failed
If we couldn't find the name on the bus or the ratbagd process already
terminated, return None and fail.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-23 08:05:17 +02:00
Peter Hutterer
572f00cf2a Add GNOME svg for Roccat Kone XTD 2017-08-23 08:04:12 +02:00
Benjamin Tissoires
330b4641ad tools: ratbagctl: have a full description of the commands in the usage
I originally intended to have a dynamic use of argparse to generate
the commands, but it turned out to be a nightmare.

Just go down the tree of arguments and format the help properly.

Fixes #288

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
c1c8b1eda2 tools: ratbagctl: fixes for parsing arguments
We shouldn't try to access input_string[0] if len(input_string) is null.
Meaning a condition in the break in the while loop could be checked
earlier (or later).

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
aa251448d3 tools: rabtagctl.devel: only output the dbus name when using keepalive
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
e27b1eb99f tools: ratbagctl: remove useless try/catch
ns is never reset, so once it has a subparser, it'll keep it, so the try
catch is just too much

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
faaf93b194 tools: ratbagctl: kill an infinite loop in parsing
Calling "ratbagctl profile -t" resulted in an infinite loop because it
tried again and again to parse "-t" in the profile

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
58957667e1 tools: ratbagctl: shout the usage if the parsing is incomplete
Too easy to trigger ("ratbagctl.devel profile" is just enough), so we
probably better have a proper usage call here.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
0db7ba0c85 tools: ratbagctl: rename .parse into add_to_subparsers
.parse did not consumed the input_string, it only appends the given
parsing to the parent. Rename the function and kill the debug output
in nested calls as this was misleading while re-reading the code.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
c42c15ad0e tools: ratbagctl: have the global options global
The help option (or verbose FWIW) were not global which makes some random
behavior when using -h at different places for the input string.

Retrieve those options once and remove them from the list of things to
process.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
fc50e38ae2 tools: ratbagctl.devel: honor --help too
Now that ratbagctl properly shows the help, the devel version should
too.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Benjamin Tissoires
b2d29a0285 tools: ratbagctl.devel: fix exception if the given arguments are wrong
"sudo ./build/ratbagctl.devel profile 2 4" returns an exception with cmd
being unknown.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-23 14:25:35 +10:00
Peter Hutterer
87ecd6e252 tools: add --keepalive option to ratbagd devel
Keeps the ratbagd daemon running until a signal is received. This is helpful
for using an external client (like piper) to run against the ratbagd.devel
instance. And to make that even easier, print the RATBAGCTL_DEVEL environment
variable for use with ratbagd.py. In the future, this should probably be a
more generic name.

The integration is a bit odd because we need to add --keepalive to the actual
parser, but we recreate that on every parse() call. So we set a flag on the
parent object and check for that during parser creation.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-22 08:17:21 +02:00
Peter Hutterer
2b49550b9b tools: ratbagctl: skip on AttributeError exception handling for --help
We default to False anyway, so it's guaranteed to be an attribute on the
parser

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-22 08:17:21 +02:00
Jente Hidskes
6ddba76c93 RatbagdButton: make mapping properties writable
This brings RatbagdButton in line with the other Ratbagd* objects, and
more importantly solves https://github.com/libratbag/piper/issues/140.
2017-08-22 10:22:51 +10:00
Peter Hutterer
d9e7298aee ratbagctl: improve the top-level --help output
Don't automatically handle the help output - call print_help() on the parser
manually.

It's unclear why this doesn't just get called correctly, but at least this
fixes the immediate issue. The subcommand help is still pretty terrible
though.

https://github.com/libratbag/libratbag/issues/288

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-21 11:06:32 +02:00
Clément Vuchener
49b7029506 hidpp: Fix error string array size
Extend error strings array so reading 0xFF as an error code would not overflow.
2017-08-18 04:26:50 +10:00
Clément Vuchener
468787601e hidpp: Distinguish 1.0 and 2.0 error codes 2017-08-18 04:26:50 +10:00
Jente Hidskes
804d8f7969 RatbagdResolution: emit properties changed from resolution_set_default
This allows clients to respond to changes in the default resolution. It's
not the cleanest approach, but it works. To clean it up, we could cache
the changed resolutions and make sure to only emit the signal on those,
just as the FIXME already notes.

References https://github.com/libratbag/piper/pull/36.
2017-08-17 10:35:09 +10:00
Jente Hidskes
9b53119121 RatbagdResolution: emit properties changed from resolution_set_active
This allows clients to respond to changes in the active resolution. It's
not the cleanest approach, but it works. To clean it up, we could cache
the changed resolutions and make sure to only emit the signal on those,
just as the FIXME already notes.

References https://github.com/libratbag/piper/pull/132.
2017-08-17 10:35:09 +10:00
Jente Hidskes
b773ac085b ratbagd.c: unlink before emitting property changed 2017-08-11 11:12:24 +01:00
Peter Hutterer
13419dcbb8 doc: drop documentation
Our DBus interface is the only API now and libratbag is just the internal
library. Let's not build doxygen for it, there's no need.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-08-02 10:14:23 +01:00
Benjamin Tissoires
c9322fa983 tools: ratbagctl.devel: do not spawn a subprocess to run a python script
We do not really care using the actual ratbagctl command, we just want
to run it. So we can simply call out the python functions directly
and live happily ever after.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-01 10:31:43 +01:00
Benjamin Tissoires
6cfca9e34b tools: share the devel boiler plate in a separate python file
We want to share as much as possible between ratbagctl.devel and
ratbagctl.test, so better have a separate file that knows how to
properly spawn the dbus daemon and terminate it.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-08-01 10:31:43 +01:00
Jente Hidskes
282398493b ratbagd_button: emit property changed on ActionType when setting mappings 2017-07-31 14:38:24 +01:00
Jente Hidskes
022dc74354 ratbagd_button: emit property changed on Macro 2017-07-31 14:38:24 +01:00
Jente Hidskes
cd6ffca413 ratbagd_button: emit property changed on KeyMapping 2017-07-31 14:38:24 +01:00
Jente Hidskes
b19a6ebcfc DBusInterface: document Macro and SetMacro 2017-07-31 14:38:24 +01:00
Peter Hutterer
811281372b ratbagd: fix return code for SetSpecialMapping (#262)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-30 14:23:25 +02:00
Benjamin Tissoires
c361b8500f test: make sure the dbus daemon is available before starting the test suite
On CircleCI, the builds fail one over four times because we are launching
the testsuite while ratbagd.devel is still not ready.

Do a basic polling after we launch the daemon so that we are aware when
the ratbagd daemon is ready.

A proper solution would be to use "new" for querying the proxy, not
"new_sync". However, this would require us to have a GTK mainloop
running, so it's a PITA.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-29 09:05:43 +01:00
Thomas Hindoe Paaboel Andersen
bcf302904d meson: allow builddir other than 'build'
Configuring with 'meson builddir' would fail with:

Program build/ratbagctl.test found: NO
Meson encountered an error in file meson.build, line 512, column 0:
Program "build/ratbagctl.test" not found or not executable
2017-07-29 08:24:21 +01:00
Benjamin Tissoires
e0e4d5062a hidpp20: fix resolution active set/get
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-28 16:19:26 +01:00
Benjamin Tissoires
abd1a04fed tools: ratbagctl: remove useless function
it was used while we were missing implementations, no it's useless.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-28 15:51:26 +01:00
Benjamin Tissoires
ab1d7628f1 tools: ratbagctl: fix 'set' processing when the device is missing
is it a hack or the correct way?

triggered by: sudo ./build/ratbagctl.devel led 0 set color ffffff

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-28 15:51:26 +01:00
Peter Hutterer
670cf90e11 ratbagd: handle SIGINT for quitting
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-28 14:48:10 +01:00
Peter Hutterer
f5210e1902 ratbagd: remove devices before removing the context
This code isn't actually hit because we don't handle signals correctly, but
once we do, ratbagd_free() will assert because the devices never get removed.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-28 14:48:10 +01:00
Peter Hutterer
5bcafb5bee Reduce to one special->special string mapping dictionary
No need to have two copies here, simply have the dict and then flip it so it
works with the strings as keys too.

The slightly odd list comprehension is because we can't add to a dictionary
while iterating through it, so we need to get everything out first.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-28 14:17:57 +01:00
Jente Hidskes
d8e132f550 tools/ratbagd.py: sync with Piper 2017-07-27 09:37:31 +02:00
Benjamin Tissoires
7e9566b00f Start dbus in the container for being able to run the test suite
We don't need a full systemd service, just dbus-daemon to be started.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-26 18:10:03 +02:00
Benjamin Tissoires
7c313a31fd tools: ratbagctl: fixes for specials
few minor issues which were unseen because driver-test was missing to set
the special key mappings

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-26 18:08:39 +02:00
Jente Hidskes
861562e58a ratbagctl: fix typo 2017-07-26 18:07:19 +02:00
Jente Hidskes
0a6b4b3778 ratbagd: change the led type to the enum 2017-07-26 18:07:19 +02:00
Jente Hidskes
b4f451285e ratbagd: change the special mapping to the enum 2017-07-26 18:07:19 +02:00
Jente Hidskes
5f0ebdead7 tools/ratbagd.py: sync with Piper 2017-07-26 10:16:55 +02:00
Benjamin Tissoires
de3bb0e579 implement resolution active set (#249)
Fixes #80

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-26 08:32:16 +02:00
Benjamin Tissoires
9dcd2c6c05 trivial flake8 fixes
whitespaces, missing RatbagdButton and more whitespaces

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 18:44:04 +02:00
Benjamin Tissoires
34196c9960 tools: ratbagd.py: add readwrite=False when we are using explicit setters
Assigning an action on a button has some side effects, and this is why we
do not have writable properties on those.
Mark the _set_dbus_property() as read only so we do not get a bunch of
PropertyReadOnly exceptions.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 18:24:10 +02:00
Peter Hutterer
5399d15658 ratbagd: add support for test device button types
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 18:24:10 +02:00
Peter Hutterer
5f98d8d029 ratbagd: rename test's button type to action_type
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 18:24:10 +02:00
Peter Hutterer
10903e2434 ratbagd: change the button type to the enum value
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 18:24:10 +02:00
Peter Hutterer
b7f53effa1 ratbagd: add macro support
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 18:24:03 +02:00
Peter Hutterer
129551f3f4 ratbagd: add support for macros in the test device
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 17:17:03 +02:00
Peter Hutterer
4f62424e8a driver-test: fix macro initialization
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 17:17:03 +02:00
Peter Hutterer
ae65ab3ae8 tools: ratbagctl: fix printing of special key map
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 17:17:03 +02:00
Peter Hutterer
96067f18ca ratbagd: change the key action types to enums
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 17:16:54 +02:00
Peter Hutterer
67e1c8667b Change enum value of the unknown value type
Keeps the values as uints

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 16:47:27 +02:00
Peter Hutterer
ab67517584 tools: fix typo - s/UNKOWN/UNKNOWN/
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 16:47:27 +02:00
Peter Hutterer
9fe892f10f tools: ratbagctl: add support for resolution default set/get
https://github.com/libratbag/libratbag/issues/246

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 12:17:15 +02:00
Peter Hutterer
bf18e9b795 ratbagd: fix resolution_set_default
https://github.com/libratbag/libratbag/issues/246

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 12:17:15 +02:00
Peter Hutterer
e95bb9601c tools: ratbagd: skip superfluous is None check
We'll throw an exception before this happens

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 12:17:15 +02:00
Jente Hidskes
a16ffa3946 DBusInterface: mark Resolution as read-write 2017-07-25 11:27:08 +10:00
Peter Hutterer
8c97a12741 Don't install ratbag-command
libratbag is now a static library only and the only exposed interface is the
DBus interface. We have ratbagctl for that interface.

ratbag-command shouldn't be installed, it becomes a pure developer tool now.
We still keep it around for that reason, but let's not install it.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 11:14:13 +10:00
Peter Hutterer
0982d6a4a9 Drop libratbag as separate library
Now that ratbagd is part of libratbag, the DBus interface is the preferred way
to interact with a device. Shipping libratbag as a .so file means we have to
worry about two ABIs when it's unlikely that anyone ever uses the libratbag.so
directly.

Make it a static library internally instead.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-25 11:14:13 +10:00
Benjamin Tissoires
3160d86050 tools: ratbagctl: do not use chevrons and report active profile
ratbag-command uses parentheses, not chevrons, and it also reports
which profile is currently active.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:09:24 +10:00
Benjamin Tissoires
6faa59c70d tools: ratbagctl: add support for separate X/Y resolutions
Big commit because of the test suite changes.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:09:24 +10:00
Benjamin Tissoires
ced958f135 hidpp10: implement enable/disable profiles
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
d5ccaed457 hidpp10: implement commit API
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
2c799eca30 hidpp10: correctly retrieve the profile directory and use it
We need to read the directory and the profiles only once.
Nothing tells us how many profiles are supported, so use the specifications
from Logitech website, and add a hwdb entry for those.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
98fb63e2e3 hidpp10: assign the active resolution when the profile is not active
Same than hidpp20.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
55bab29233 hidpp20: enable/disable profiles and report it correctly
Bunch of errors while processing the dictionary of enabled profiles.
Got everything working out quite well on the G900 and G403, so I guess
others should behave properly.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
c0c77100ad ratbagd: implement enable/disable profile
We also maps the commands to ratbag-command.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
aa50df8eaf tools: ratbag-command: fix enable/disable profiles
The usage help is wrong, it's not how it works.
It'll be too much pain to fix it the other way around, and I prefer
using "ratbag* profile N enable" than "ratbag* profile enable N".

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Benjamin Tissoires
c12ca6008a tools: ratbagctl: add missing commits
On devices supporting the commit API, ratbagctl did not write anything
to the device.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-25 11:06:59 +10:00
Peter Hutterer
c6bc6b2576 tools: ratbagd: don't silence UnknownProperty errors
Now that we've moved all properties to read-write where required, unleash the
exception again - any UnknownProperty error is now a bug.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
f53bf7d4ad ratbagd: make the LED properties writable
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
40bd189cc0 ratbagd: make the resolution properties writable
This also drops the separate x/y properties and instead just returns a tuple
for "Resolution".

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
7097f1dea6 ratbagd: remove GetResolutionByIndex
This is superfluous, it's trivial enough to get the Resolutions property and then
work with that. We're not talking about a huge amount of data anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
70f3da98db ratbagd: add IsActive/IsDefault to Resolution
This replaces the calls in the profile.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
f281bd751e ratbagd: drop 'GetProfileByIndex'
This is superfluous, it's trivial enough to get the Profiles property and then
work with that. We're not talking about a huge amount of data anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
04b54d26e2 ratbagd: add 'IsActive' property to the profile
Instead of a GetActiveProfile in the device, make this a property of the
profile. The SetActive method stays around, it's less prone to mis-use than
the property since we cannot allow a caller to go "profile.is_active = False"

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
19cdf6d7e9 ratbagd: drop SvgPath property from device
Obsolete now that we have theme support, use GetSvg() instead

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
0018431f31 ratbagd: remove DeviceNew/DeviceRemoved signals
Our device list is so small that having separate signals is a bit pointless,
updating the property should be sufficient.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
8380e1686b Tidy up the dbus documentation
Use more sectioning and more precise descriptions of the function signatures.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
c14ffe36e3 ratbagd: send a PropertyChanged signal when modifying the device list
We have DeviceAdded and DeviceRemoved signals but given the expected number
of devices (less than 2 in most cases) it's easier to just update the Devices
property. The DeviceAdded/Removed signals stick around for now, they will be
removed later.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
a4dd9bcdf3 ratbagd: change the remote property value when writing a property
set_cached_property merely updates the proxy's own copy, it doesn't do
anything to the remote. Manually call the DBus.Properties.Set interface
to do that.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 11:36:09 +02:00
Peter Hutterer
c1cabeeeeb meson: reduce the valgrind test timeouts
Factor 5 should be enough, factor 100 is a bit excessive

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
ca69365a86 meson: run ratbagctl.test as part of ninja test
Or at least do so when we're root.

Test is skipped on CircleCI because we don't have DBus.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
98fa9c168a tools: ratbagd: throw an error if the system bus is unavailable
When running in a container (CircleCI), dbus may not be available. Throw one
of our errors to be consistent with our behavior when the name owner isn't
available.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
0e26b6e2be tools: ratbagctl: check ratbagd for immediate exit before continuing
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
760c3f3ff9 tools: ratbagctl: Fix typo in comment
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
8aaa6894df tools: ratbagctl: don't start a shell for ratbagd's subprocess
This is not required.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
636d254d41 tools: ratbagctl: remove duplicate subprocess.terminate() call
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
f6e5dd6c2c test: disable core dumps in the test suite
No need for this to end up in the journal

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
5637755345 Only reset the driver to NULL on unusual exits
If a driver succeeded but then fails sanity checks, leave the driver set and
let the cleanup code handle the rest. Otherwise, memory allocated by the
driver's probe() function is never released.

Fixes a valgrind memory leak complaint when running tests for invalid devices
(e.g. device_profiles_num_0).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 10:32:41 +02:00
Peter Hutterer
a9c4f46412 ratbagd: change the led path to .../event4/p0/l0 (#240)
Was using 'b0' as enumerator, copy-paste error from the button code. Switch to
'l0' to make it easier to differentiate in d-feet or other dbus viewers.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-24 06:58:30 +02:00
Peter Hutterer
7aed3640c4 tools: ratbagctl: hook up report rate argparsing
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-21 10:12:07 +02:00
Peter Hutterer
85f2ec3910 tools: ratbagctl: compress two print statements into one
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-21 10:12:07 +02:00
Peter Hutterer
6274dea4ac meson: add ratbagd.py as input source for merge_ratbagd.py
Otherwise we won't notice changes to it

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-20 07:09:28 +02:00
Peter Hutterer
a938521c9e ratbagd: use zalloc instead of calloc
Because we really don't care about OOM beside blowing up.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
9450d1402f Move the _cleanup_ functions over to shared-macro.h
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
8209ce56b6 Move a few #defines over to shared-macro.h
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
a6d03fde18 ratbagd: use strdup_safe for all string copies
Because if we can't strdup a device name or dbus path, we have problems we
can't recover from anyway.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
5fff0ece5b tools: include config.h from lur-command
Removes duplicate GNU_SOURCE define

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
d915fdfe45 Include shared-macro.h from libratbag-util.h
These headers need merging at some point, for now just include it and remove
the duplicates.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Peter Hutterer
7b861ada4c Move the shared sources from ratbagd into src
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-19 10:09:01 +02:00
Benjamin Tissoires
fa1799eef3 tools: copy ratbagd.py from piper and integrate it in ratbagctl
We are using a custom python script to generate the final ratbagctl
so we can strip out the headers.

Now merging and testing ratbagd.py in piper will be easier than ever.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-19 08:39:29 +02:00
Peter Hutterer
77cc2fa82d Add logitech G303 SVG for gnome theme (#228)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-18 13:15:48 +02:00
Benjamin Tissoires
de4bd4a2d2 tools: ratbagctl tests: do not spawn a new process for each call
This reduces the time to run the tests from (now with previous commit) 10s
to a mere 2 seconds.

The --subprocess argument is voluntarily masked from the help message,
because I couldn't figure out how to add it to the unittest parser.
And OTOH, we should not run in subprocess unless debugging...

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-18 19:33:32 +10:00
Benjamin Tissoires
c61782f1a4 tools: ratbagctl: Sync ratbagd.py with piper
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-18 19:33:32 +10:00
Benjamin Tissoires
6503407007 tools: ratbagctl: add missing capabilities strings
Prevents some failures while showing the information of the devices.

Fixes de16f1a4b1

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-18 19:33:32 +10:00
Jente Hidskes
09295d9d0e data/gnome/logitech-g700: fix overlapping paths
See https://github.com/libratbag/piper/issues/48
2017-07-18 17:52:43 +10:00
Jente Hidskes
2c379d09c9 data/gnome/README: include note on z-ordering
As discussed in https://github.com/libratbag/piper/issues/48
2017-07-18 17:49:25 +10:00
Jente Hidskes
994ade7fff data/gnome/logitech-502.svg: fix text alignment of button5-leader 2017-07-18 17:04:20 +10:00
Peter Hutterer
769289fe01 circleci: use fedora-latest, not rawhide
Otherwise we get build errors when rawhide is broken, like today. Not worth
chasing that moving target.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-14 09:11:14 +10:00
Jente Hidskes
f05950f37c RatbagdLed: emit DefaultResolutionChanged on the resolution's object
path

See https://github.com/libratbag/piper/pull/36#issuecomment-315065722
2017-07-14 08:33:36 +10:00
Peter Hutterer
de16f1a4b1 Set the parent capabilities before setting any child ones (#223)
Any specific capability like 'switchable resolution' requires the basic
'resolution' capabilty to be set.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-13 09:17:14 +02:00
Peter Hutterer
d1db382607 ratbagd: drop caching of libratbag variables (#222)
Instead of copying them into our own struct, just query libratbag when we need
them. This brings the resolution code in line with the button and LED code
which don't do caching either.

Eventually we may want to cache them again to detect changes behind your
back (if libratbag value != our cached value) but for now this reduces the
work ratbagd does.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-13 08:29:58 +02:00
Peter Hutterer
82a0cd4ec4 ratbagd: send property changed signals when we change the properties
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-13 07:02:08 +10:00
Clément Vuchener
ec85b6db3e hidpp20: Fix changing flags in hidpp20_special_key_mouse_set_control
The first bit of each pair set is new state for the flag, the second must be set for the change to be made.
2017-07-12 09:05:11 +02:00
Clément Vuchener
a9f4049841 driver-hidpp20: do not divert button when remapping
Temporary diversion has priority over remapping and should not be set at the same time.
2017-07-12 09:05:11 +02:00
Benjamin Tissoires
dab5d2c0b7 ratabgctl.test: reset the test device before each test
Now that we have a method which resets the device, use it so we can
rely on the state of the device.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
51d625244d ratbagd: add a method to reset the test device to its defaults
Make sure we keep the defaults as such by duplicating them in
driver-test.c (and mark the input data as const).

Add a dbus method to reset the test device from the caller.
This is much useful when running tests given we have no guarantees on the
ordering.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
7b1e7dc4e7 tools: add a test suite for ratbagctl
Using unittest to be fancy

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
019d020535 tools: ratbagctl: output device information like ratbag-command
Better having a consistent device information across tools.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
89d071bb80 Fix flake-8 complains
Piper already uses this, we might as well.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
499ebc7d18 tools: ratbagctl: sync ratbagd bindings with piper
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
e522e0bb07 drivers: add a fallback for fetching the SVG name
In case the udev property is not present, we might want to query
the driver for the SVG name.
This is useful for driver-test as there is no udev device attached to
it, and for hidpp20 as we have auto-detection. We should then be able
to implement this in hidpp20 also so that the name gets automatically
created.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
f55a314666 ratbagd: add a test device while in developer mode
This allows to run tests against a device without having a proper device
plugged in.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Benjamin Tissoires
97ac0f81f2 hidpp20: shut one ratbagd warning
If the profile is not active, we do not know which resolution is currently
used. Instead of having ratbagd complaining, just set the default as
active.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-12 08:16:39 +02:00
Peter Hutterer
8cfcab3363 circle.yml: add ninja scan-build to the jobs
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
6f72accbee circle.yml: split fedora install out and make ninja more flexible
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
e021937867 Change device name to use a stack buffer
This shuts up a scan-build warning about a memleak that looked like a false
positive but I couldn't get rid of.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
82d197462f hidpp20: fix NULL-pointer dereference warning
rc may be a negative errno or a positive hidpp error code. If the latter we
used to continue with a NULL macro pointer, eventually crashing.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
78bdfe7a59 Don't allocate zero-sized memory
Triggered by the tests with 0 resolutions

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
586fc7a97d hidpp20: squash memory leak on profile initialization error
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
2faa94920e hidpp20: drop unused argument from the profile destroy function
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
01163d8f77 ratbagd: fix a false-positive unused variable warning
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
04990e4ea2 hidpp10: error out if we deal with unsupported profiles
Just logging and error and continuing is not enough, we'll eventually
dereference garbage values.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
37c8dec45c Fix the various scan-build warnings for dead assignments
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Peter Hutterer
df2a06690d Fix device capability check
We now have a lot more bits to cater for, so let's use an array.

Broken with 487e66e64d

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-11 10:50:22 +02:00
Jente Hidskes
2c4cdc6dc6 ratbagd-led: mark DBus properties as EMITS_CHANGE 2017-07-10 20:41:12 +10:00
Jente Hidskes
96c2f404d2 ratbagd-led: add error check for RGB 0-255 range 2017-07-10 20:41:12 +10:00
Clément Vuchener
e33a515fd6 data: add toned-down SVG for Logitech G500/G500s (#214)
* data/gnome: add SVG for Logitech G500/G500s

* data/gnome: add buttons 0 and 1 to the G700
2017-07-10 09:30:56 +02:00
Jente Hidskes
8fc58e259c Use toned-down device SVGs (#182)
* data/gnome: add GNOME theme requirements

* data/logitech-g403.svg: add G403 GNOME SVG

* data/logitech-g502.svg: add G502 GNOME SVG

* data/logitech-g700.svg: add G700 GNOME SVG

* meson: install GNOME SVG files
2017-07-07 16:05:36 +02:00
Christian Kellner
caadd86091 hwdb: add G403 entry
The G403 comes in a (optional) wireless version too; the dongle
that come with it has the product id c539, which is already
handled and also works (by the G900) entry.

Signed-off-by: Christian Kellner <christian@kellner.me>
2017-07-07 15:12:55 +02:00
Jente Hidskes
e16aafe86c data: move default SVGs under default/ subdirectory..
.. and install them in the appropriate directory after #209
2017-07-07 15:07:45 +02:00
Peter Hutterer
6a0ebe9e45 ratbagd: add support for svg theming
Two new DBus interfaces:
org.freedesktop.ratbagd1.Manager.Themes -> string array
org.freedesktop.ratbagd1.Device.GetSvg('theme') -> string

The Themes property is a static list of available themes. These are currently
hardcoded in ratbagd, but the theme 'default' is guaranteed to exist.

The GetSvg() method takes a theme name and returns the full file path to the
themed SVG.

Longer-term this will deprecate the Svg and SvgPath properties in the Device
but for now we leave them there.

https://github.com/libratbag/libratbag/issues/204

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-07 08:20:01 +02:00
Benjamin Tissoires
79f4b9c0d6 tools: add ratbagctl.devel to launch both ratbagd and ratbagctl
When developing with ratbagd, we need to test against master, not
the system-wide installed daemon.

Allow to name space ratbagd with the creation of a new (not installed)
rabtagd.devel daemon, that is tagged with the git sha of the ratbagd
folder.

Handle this namespace in ratbagctl by looking at an environment variable
RATBAGCTL_DEVEL.

Then provide a python script that launches both rabtagd.devel and
ratbagctl with the correct environment variable set so that they can
talk to each other.

Note that we blindly overwrite the dbus .conf file as nobody else than
developers should have one.

Note: the tagging of ratbagd.devel (like the meson bit) won't run unless
a rebuild is triggered. So we don't necessarily always get the right git
tag. However, touching ratbagctl.in triggers a rebuild, so we should be
OK-ish.

Fixes #206

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-07 16:02:46 +10:00
Benjamin Tissoires
e6433abd09 tools: import ratbagd.py from piper
We are updating it, let us keep it in sync

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-07 16:02:46 +10:00
Peter Hutterer
96f3b7858b tools: fix ratbagctl error when dbus isn't available (#210)
File "./build/ratbagctl", line 713, in main
    cmd.func(r, cmd)
UnboundLocalError: local variable 'r' referenced before assignment

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-06 08:39:27 +02:00
Peter Hutterer
f5abc191d8 ratbagd: drop the ActiveResolutionChanged signal generation (#208)
* ratbagd: drop the ActiveResolutionChanged signal generation

Leave the signal in the DBus API for now so we can hook it up later, but
stop the signal being generated. Changing the dpi does not change the active
resolution.

https://github.com/libratbag/libratbag/issues/205

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>

* ratbagd: fix signal dbus interface name

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-06 08:20:43 +02:00
Benjamin Tissoires
251b602323 ratbagd: call the correct set_resolution based on the capabilities
ratbagd unconditionally called set_resolution_xy while libratbag expects
the caller to check on the capabilities. Instead of letting this burden
to the dbus user, have ratbagd handle this for us.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-05 11:33:21 +02:00
Peter Hutterer
fe3169182c meson: fix valgrind setup
The previous approach had no effect, it wasn't doing things correctly.
Add a proper valgrind setup, run with:

       mesontest --setup=valgrind

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
[fixed rebase conflict]
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-05 09:36:30 +02:00
Peter Hutterer
642a5339bc meson: drop invalid configuration: tag for install_data
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-05 09:35:51 +02:00
Benjamin Tissoires
c251053f03 circle.yml: add workaround for meson upstream bug
Meson currently doesn't clean up after itself on uninstall.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-05 08:37:18 +10:00
Benjamin Tissoires
4b97b00518 circle.yml: uninstall and checks if there are any leftovers
Check if $PREFIX is still there after uninstall, and if so show
which files are left.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-05 08:37:18 +10:00
Jente Hidskes
faa1a24c25 RatbagdDevice: add commit method
Fixes #198
2017-07-04 17:02:18 +02:00
Benjamin Tissoires
b78b5cd73e circle.yml: add install step
It doesn't cost much to actually install the files, so we can check
where they are installed.

Also add mesonconf before building so we can see in the logs
the various configure environment.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-03 19:14:10 +10:00
Peter Hutterer
4eb5411bf1 meson: fix svg data dir (#191)
It was missing the prefix

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-03 10:28:20 +02:00
Peter Hutterer
22af1176d3 meson: hack around Fedora's systemd libdir confusion
Fedora uses /usr/lib64 as libdir but systemd uses /usr/lib for its files. We
used libdir to install the unit files, which then end up in
/usr/lib64/systemd/systemd where it will be ignored. There's no good way to
avoid this beyond detecting this mismatch and hacking around it.

To keep custom prefixes intact, this patch detects a /usr prefix and checks
with systemd's pkconfig, if the libdir and the systemd unitdir mismatch, then
we adjust the path.

https://github.com/libratbag/libratbag/issues/188

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-07-03 09:57:20 +02:00
Benjamin Tissoires
bb6d8a6ea4 update circle CI link 2017-07-01 17:43:26 +02:00
Benjamin Tissoires
935f68ae8f enhance circle.yml with workflows
Circle CI uses docker, so nothing prevents us from running several
tests in parallel for different distributions. Ideally, we should also
be able to test the install and be sure we can talk to ratbagd
with the dbus activation on those various distributions.

This version runs both Fedora rawhide and Ubuntu 17.04 at the same
time.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-07-01 10:38:01 +10:00
Peter Hutterer
2fd939f514 resolution: add support for min/max resolutions
https://github.com/libratbag/libratbag/issues/180

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 09:07:24 +02:00
Peter Hutterer
dbc0672061 README: clarify the two developer-specific notes
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 07:24:54 +02:00
Peter Hutterer
804f2eec76 README: clean up the Running ratbagd section
We install everything, so rather than having commands that aren't needed,
simply describe what we're doing and hope for the best.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 07:24:54 +02:00
Peter Hutterer
73c24319d1 README: move the dbus interface description out
No-one reads anything longer than 140 char anymore, so let's move the DBus
Interface description out. The average visitor to this site won't care.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 07:24:54 +02:00
Peter Hutterer
6b3fc6338e README: cleanup, de-duplication, etc.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 07:24:54 +02:00
Peter Hutterer
c6855df5fc Drop the semaphore status in the README and the build script
Semaphore only provides Ubuntu 14.04 which is too old for us. We now have
CircleCI integration which can run docker images, so let's leave that and drop
Semaphore.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-30 07:24:54 +02:00
Benjamin Tissoires
9ed61fd072 Add circle.yml
Semaphore CI is still using Ubuntu 14.04, and the shipped systemd version
is just too old.
OTOH, Circle CI 2.0 (still beta as of today) allows to use any docker
image as a base for running the tests. Meaning that we can have a fedora
rawhide image as a base and we do not have to handle the update of systemd
meson and others.

Ship a basic circle.yml for Circle CI to run our tests and add the badge
in the README.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-06-30 07:53:22 +10:00
Benjamin Tissoires
1a764944e7 Merge pull request #184 from whot/wip/ratbagd-merge
This merges ratbagd into libratbag, keeping the histories of both projects intact (hence the rather large merge). The meson.build files are merged and a few things are shuffled around to look like one normal project directory. The build artifacts are still the same, i.e. we still build libratbag and ratbagd.
2017-06-29 17:19:30 +02:00
Peter Hutterer
e311f89357 Provide a min/max dpi for the resolutions
For a GUI application like Piper, it's required that we know the range to
present to the user.

This patch includes the code for HID++ 1.0 and 2.0, other drivers need to
follow.

https://github.com/libratbag/libratbag/issues/180

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 09:07:18 +02:00
Peter Hutterer
ecdba84977 hidpp20: use min/max macros over ternary condition
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 09:07:18 +02:00
Peter Hutterer
c003eccb1e hidpp10: fix a comment, dpi_table is not null-terminated
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 09:07:18 +02:00
Peter Hutterer
f36fdc0492 meson: drop the separate shared library for ratbagd
We can reinstate that when we need it

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:03:11 +10:00
Peter Hutterer
907b96d447 meson: drop unused defines
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:03:11 +10:00
Peter Hutterer
b4682e836c ratbagd: move the source from ratbagd/src to just ratbagd/
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:02:56 +10:00
Peter Hutterer
30e8fbedd8 Drop separate ratbagd COPYING file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:02:38 +10:00
Peter Hutterer
fc1887c01f Merge ratbagd README into libratbag
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:01:08 +10:00
Peter Hutterer
d51acfd730 Move ratbagd dbus and tools to top-level directory
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:01:07 +10:00
Peter Hutterer
35e38a5469 Merge ratbagd's meson file into libratbag's
I couldn't get the subdir() to work, it would throw exceptions somewhere
internal to meson. So instead, just merge the two together.
This still builds everything as before, it's just a single meson file now.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-29 15:01:05 +10:00
Peter Hutterer
2ae3976868 Merge ratbagd into libratbag 2017-06-29 14:59:13 +10:00
Jente Hidskes
5dcdc3c652 Add an API for LEDs 2017-06-29 11:56:37 +10:00
Peter Hutterer
af68f6046c Fix a doxygen reference
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-20 14:07:28 +10:00
Jente Hidskes
c0c4ba156a README: fix install instructions
The instructions still referred to in-source builds. Meson instead uses
an out of tree build directory, hence we update the paths to point to
the build directory.

Fixes #32.
2017-06-14 10:52:41 +02:00
Jente Hidskes
22135f31d5 ratbagd-device: update for new capabilities in libratbag
Fixes #29.
2017-06-12 18:49:44 +10:00
Raghavendra Kamath
0c7ca85f5b Add new artwork of Logitech G9 2017-06-10 12:25:07 +10:00
Raghavendra Kamath
478c5bbb68 Adjust text and resolution in svg.
To make the text look consistent font size is now set to 12pt in all svg & default resolution is adjust according to new inkscape (0.92) defaults
2017-06-10 12:25:07 +10:00
Peter Hutterer
487e66e64d Group the the capabilities and provide some more generic topic-like caps
This makes code that just checks for general abilities easier to write, the
specific thing we can do (e.g. switch profiles) is expressed as separate bit.

This is an ABI break

Related to #172

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-09 08:51:26 +02:00
Jente Hidskes
2b5b0b1772 Fix boolean instruction for Meson
https://github.com/libratbag/libratbag/issues/175
2017-06-08 12:30:02 +02:00
bentiss
13bb5b52e1 Fix boolean instruction for Meson
Fixes issue #175

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-06-08 11:14:52 +02:00
Peter Hutterer
90d2a48cfb ratbagctl: default to list-devices without argv
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-08 09:15:21 +02:00
Peter Hutterer
97a37d21e1 Drop the python bindings, move them into ratbagctl
The python bindings were mostly boilerplate and a 1:1 mapping of the dbus
interface anyway. Packaging them for distributions is difficult, so given how
little benefit they provide, let's just stop shipping them.

Those who need those bindings (like piper) can either make their own or copy
them.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-08 09:15:21 +02:00
Peter Hutterer
9cf6100e00 python: switch ratbagctl shebang to python3
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-06-07 09:19:05 +02:00
Benjamin Tissoires
932cf905ef ratbagd 0.4
- changed licence of rb-tree to have a consistent MIT licence
- new signal for active resolution changes

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2017-06-06 16:04:39 +02:00
Peter Hutterer
ad88f755a4 shared: relicense rbtree to MIT
To avoid having multiple licenses within a project as small as ratbagd, and to
avoid having to deal with any fallout from mixing MIT and LGPL.

Pre-approved by David Herrmann who wrote that code, see
https://github.com/libratbag/ratbagd/issues/23#issuecomment-302741861

Fixes https://github.com/libratbag/ratbagd/issues/23

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-05-29 13:52:38 +02:00
Jente Hidskes
dd71c23a04 resolution: add set_default method
Fixes #8.
2017-05-23 13:30:21 +10:00
Jente Hidskes
299c49c291 README: remove ambiguity in signal descriptions 2017-05-17 12:50:35 +10:00
Jente Hidskes
b1feabaf64 resolution: add signal for active resolution changes
This implements a signal that is fired whenever the active resolution
changes. For now the signal is only fired when the resolution changes
through the setter, ratbagd_resolution_set_resolution, as profile changes may
not always be hooked up in the hardware.

Reference #8.
2017-05-17 12:50:35 +10:00
Jente Hidskes
2722e008e0 profile: add signal for active profile changes
This implements a signal that is fired whenever the active profile
changes. For now the signal is only fired when the profile changes
through the setter, ratbagd_profile_set_active, as profile changes may
not always be hooked up in the hardware.

Fixes #7.
2017-05-17 12:50:35 +10:00
Benjamin Tissoires
178b08cd0a ratbagd 0.3
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
2017-05-12 16:35:41 +02:00
Jente Hidskes
4dc15451b7 README: s/make install/ninja install/ 2017-05-09 14:38:38 +02:00
Jente Hidskes
3a764b6aae README: replace configure switches with mesonconf switches 2017-05-09 14:38:38 +02:00
Jente Hidskes
190e78c79c README: small documentation fixes 2017-05-09 14:38:38 +02:00
Peter Hutterer
2750f8c49b Mark the unknown button type as explicit fallthrough
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-05-09 07:50:21 +10:00
Peter Hutterer
57ffc9c5d3 meson: drop a bunch of compiler flags
These all affect the final executable and should be under the control of the
distro.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-05-09 07:50:21 +10:00
Jente Hidskes
a2b858008f meson: use join_paths with dbusdir for consistency 2017-05-08 20:44:30 +10:00
Jente Hidskes
28956126ec meson: correctly install service files
https://github.com/libratbag/ratbagd/issues/18
2017-05-08 20:44:30 +10:00
Peter Hutterer
44471d3c42 meson: use warning_level=2 instead of manual -Wall -Wextra
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-05-02 10:14:50 +02:00
Peter Hutterer
fa12517fb2 Drop autotools
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-26 10:13:56 +02:00
Peter Hutterer
9624d1bdcd Add meson build file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-26 10:13:56 +02:00
Peter Hutterer
8f7bf150df Use automake to generate ratbagctl
All we do is a single sed, we can leave that to automake.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-26 10:13:56 +02:00
Peter Hutterer
f5270e1539 Change the sed replacement for meson's benefit
No functional changes

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-26 10:13:56 +02:00
Peter Hutterer
8944353716 Update for new caps in libratbag 0.6
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-25 08:26:14 +02:00
Peter Hutterer
53ff42ea55 README: remove the compilation instructions for systemd
By now you should have 229.

And replace the instructions with actual ratbagd build instructions.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-25 08:26:14 +02:00
Peter Hutterer
25a92e61ef configure.ac: drop xslt check
Some leftover from the triassic period or so

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-24 10:13:22 +02:00
Peter Hutterer
70a33ec78d Drop AM_MAINTAINER_MODE
This isn't useful

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-24 10:13:22 +02:00
Peter Hutterer
d358d7433b Include config.h before anything else
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2017-04-24 10:13:22 +02:00
Jente Hidskes
617cd628ea python: replace == None with is None
== checks for value equivalence, but in this case what we
really want is address equivalence. Hence we use is.
2017-03-31 08:22:21 +10:00
Jente Hidskes
9601ba1323 python: catch more DBus exceptions
Gio.bus_get_sync may return None when the DBus service is not available (see
libratbag/piper#2). In addition to this, the service may time out when it is
being started in which case Gio.DBusProxy.new_sync will raise a GLib.Gerror.

This commit checks for both scenarios and raises a RatbagdDBusUnavailable
exception when either one of them occurs. This will in turn be caught in for
example Piper to properly deal with this.
2017-03-31 08:22:21 +10:00
Stephen Kitt
fc874c0249 Add manpages for ratbagctl and ratbagd
Signed-off-by: Stephen Kitt <steve@sk2.org>
2016-10-07 11:17:44 +02:00
bentiss
a9dc630fae Merge pull request #10 from whot/master
dbus cleanup
2016-03-17 09:14:41 +01:00
Peter Hutterer
d874a2e5f1 ratbagd 0.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-16 10:12:09 +10:00
Peter Hutterer
a658b117a7 device: add support for QUERY_CONFIGURATION device capability
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 14:40:44 +10:00
Peter Hutterer
638b505ade manager: drop GetDeviceById
We don't really expect more than 2-3 devices even on a test box. This function
serves little purpose, we can easily require a caller to just get all devices
(usually just one anyway) and then go from there.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 13:39:28 +10:00
Peter Hutterer
ff3730f3fb device: use "Name" instead of "Description"
This is the terminology used in libratbag as well (and everywhere else where
we deal with input devices).

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 13:29:19 +10:00
Peter Hutterer
00f488dc13 resolution: switch the capabilities to an enum
Strings can suffer from locale issues, the official recommendation for DBus
APIs is to use enums here.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 13:12:18 +10:00
Peter Hutterer
ca2f32ea58 device: switch the capabilities to an enum
Strings can suffer from locale issues, the official recommendation for DBus
APIs is to use enums here.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 13:12:18 +10:00
Peter Hutterer
0ebbccc6cf ratbagctl: fix error when printing separate x/y resolutions
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 12:23:44 +10:00
Peter Hutterer
7c622ecc58 Adjust for new libratbag 0.4 API
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-15 10:18:23 +10:00
Peter Hutterer
917308d24d Document the DBus interface in the README
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-14 17:02:17 +10:00
Peter Hutterer
97eee9e0c5 ratbagd 0.1.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 12:02:19 +10:00
Peter Hutterer
5cc234e27e configure.ac: add missing AC_SUBST for the dbus config dir
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 11:27:16 +10:00
Peter Hutterer
2bbcc51a8b ratbagd 0.1.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 10:40:01 +10:00
Peter Hutterer
1824b977f7 Fix typo in README
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 09:17:34 +10:00
Peter Hutterer
99011fd3bf configure.ac: fix dbus install directories
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-11 09:16:48 +10:00
Peter Hutterer
346631cd75 Skip the manual NULL assignment after unref
libratbag guarantees that unref() always returns NULL

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 13:03:56 +10:00
Peter Hutterer
8517e103b0 ratbagd 0.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
815a81a610 Spice up the README a bit
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
20b9339620 README: update install instructions for dbus
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
2e93ac07f6 Update gitignore for a few things
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
f385622ec6 Makefile: add a comment marker for the dbus/systemd config files
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
de83186c3c Create the dbus directory in $builddir
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
fa0d57dd47 Install the dbus config as well
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-10 12:05:40 +10:00
Peter Hutterer
b164fa622f Change to a dbus-activated service
We don't shut down once activated but that doesn't mean we need to run when
never requested.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
2016-03-10 12:05:40 +10:00
bentiss
e4c654841b Merge pull request #3 from whot/master
fix cleanup code  and restart on abort
2016-03-09 09:41:26 +01:00
bentiss
a411248c7c Merge pull request #2 from whot/wip/pkg-cleanup
minor autotools cleanup
2016-03-09 09:39:45 +01:00
Peter Hutterer
a066203b4a systemd: fix typo in service file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-09 14:08:20 +10:00
Peter Hutterer
819c70fa9a systemd: restart on abort
Now that we clean up properly, the most common crash should be fixed. Restart
on abort by default so ideally all we need to do is restart piper or whatever
consumes the API.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-09 13:45:03 +10:00
Peter Hutterer
9f9383e6ff profile: free the buttons/resolutions on profile cleanup
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-09 13:45:03 +10:00
Peter Hutterer
70222b3033 Use PKG_CHECK_VAR to check for the pkgdatadir
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-09 13:10:14 +10:00
Peter Hutterer
5e2d7de6c2 configure.ac: remove a couple of unused items
This configure.ac is largely a copy from systemd so it included things that we
don't use locally.
- we don't use grep, awk or ln
- AC_SYS_LARGEFILE and AC_CANONICAL_HOST are unecessary
- pkg.m4 - if that's missing you don't have pkgconfig installed. stop trying
  to build things then :)

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-09 13:04:22 +10:00
Peter Hutterer
aceef4d0d0 ratbagd 0.0.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-04 14:27:18 +10:00
Peter Hutterer
654956baa6 Fix distcheck
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-04 14:27:08 +10:00
Peter Hutterer
212ab08c15 device: export the full path to the SVG as well
Exporting just the filename requires the caller to know where that file sits.
That's useful for things like e.g. icons where callers may several sets to
chose from but here most callers will just use the default svg provided by
libratbag.

Export that, so that we don't have build-time dependencies in the callers just
for that single path.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-04 08:54:26 +10:00
bentiss
18a0be561f Merge pull request #1 from whot/python-bindings
Add a python module for ratbagd, replace ratbagctl with a python version
2016-03-03 15:30:19 +01:00
Peter Hutterer
0528981a0a Replace ratbagctl with a python version
It's a lot easier to interact with ratbagd from a python script than it is
with C code. Plus this means we test the bindings whenever we use ratbagctl.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-03 20:13:10 +10:00
Peter Hutterer
eac1e91638 Add a python module to talk to ratbagd
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-03 20:12:48 +10:00
Peter Hutterer
a8600faeb3 button: use dash, not underscore, for button type names
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-03 15:11:29 +10:00
Peter Hutterer
9c33eede5c Add a COPYING file
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-03-03 14:56:37 +10:00
Peter Hutterer
6c285fa2a1 button: emit property change events when we update a button
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 13:55:58 +10:00
Peter Hutterer
d6116e00bc ratbagd 0.0.1
This reverts the version number but ratbagd is nowhere near stable (because
libratbag itself isn't stable yet) and the dbus API can change at any time.
I'm not committing to keeping the current dbus API around for backwards
compatibility reasons.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 10:24:47 +10:00
Peter Hutterer
c54b382775 Require libratbag 0.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 09:59:51 +10:00
Peter Hutterer
184e2b646c Add a systemd service file
We don't have dbus-activation yet, so just define it as a normal dbus service
for now.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-29 09:54:00 +10:00
Peter Hutterer
8a8379c7eb button: return -1 for invalid special values
Otherwise it looks like the function doesn't exist

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-25 15:23:58 +10:00
Peter Hutterer
8e8d827e00 Export button mappings over dbus
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-24 12:40:49 +10:00
Peter Hutterer
2fad2e3ccd resolution: mark the dpi/rate as changable
And make sure we actually save the new value too

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-22 13:29:02 +10:00
Peter Hutterer
4c66d7f5ba dbus: allow normal users to talk to ratbagd
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-22 09:42:47 +10:00
Peter Hutterer
124385fc31 ratbagctl: print all properties
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
5fe39f94ab ratbagctl: fix show-profile to handle the resolution objects
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
e8d1645150 ratbagctl: Switch ActiveProfile parsing to an integer
Fallout from c04f1b57aa

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
d1ea517f9a ratbagctl: drop DefaultProfile parsing
Dropped in d049c13062

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
c6627d6266 device: if we can't fetch the description or svg, return an empty string
Less exception handling needed on the client side.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
2138ab05e5 Replace fprintfs with a new log_error helper
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
ce3038fd8e Use streq over strcmp
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
555d00c9a8 ratbagd: if --verbose is specified, set libratbag to verbose too
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:33 +10:00
Peter Hutterer
12f013681a Add rudimentary for buttons
This just exports the button index so far and makes sure we can write clients
that deal with button objects instead of making stuff up to test for buttons.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-19 15:32:03 +10:00
Peter Hutterer
7a498310e2 resolution: remove unused variables
Copy/paste leftover from the profile.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-18 15:14:15 +10:00
Peter Hutterer
9af58224fa resolution: export capabilities as dbus properties
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-18 11:14:13 +10:00
Peter Hutterer
61abdb57a7 device: export all capabilities as dbus properties
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-18 11:12:00 +10:00
Peter Hutterer
e0cb0c70e1 README: fix typo, this is ratbagd, not libratbag
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-18 09:12:36 +10:00
Benjamin Tissoires
420a05cabf README: Add instructions to have libsystemd >= 227
Works on F23. There are few dependencies pulled by configure that I did
not put there.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-18 09:12:33 +10:00
Peter Hutterer
262dd532e6 Add a log_verbose logging function for debug output
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-17 10:33:20 +10:00
Peter Hutterer
80ed6d1399 resolution: switch to an index for ActiveResolution/DefaultResolution
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-16 17:00:27 +10:00
Peter Hutterer
c04f1b57aa device: switch active profile over to return an index only
Returning the object path makes it harder for the client to identify which
object is the active one. A simple index into the devices array is easier to
handle.

Note: another approach was to have an IsActive property on the profile
directly. This would require updating all properties when the active profile
is changed, it's simpler to just have one index.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-16 17:00:27 +10:00
Peter Hutterer
7aca92f2b3 resolution: add support for setting resolutions and report rate
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-16 09:56:12 +10:00
Peter Hutterer
e199278d6f profile: switch DefaultResolution/ActiveResolution over to an object path
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:36 +10:00
Peter Hutterer
f2a55bca55 profile: add GetResolutionByIndex
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:35 +10:00
Peter Hutterer
bcd62aec6b resolutions: switch to using objects for resolutions
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:23 +10:00
Peter Hutterer
c4e4330bd1 profile: prefix the profile object path with a 'p'
sd_bus_encode_many() escaps elements starting with a digit so our 0 profile
has an object path of /.../_30. This is quite confusing during debugging.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:12 +10:00
Peter Hutterer
c70b53a162 profile: add support for setting the active profile
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:11 +10:00
Peter Hutterer
3262def07c device: add support for get-svg
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:11 +10:00
Peter Hutterer
d049c13062 device: drop default profile fetching, removed from libratbag
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2016-02-15 15:17:01 +10:00
Peter Hutterer
5ffed21e0e Remove cleanup func define for sd_bus_message_unref
Added to systemd in 4afd3348c7506dd1d36305b7bcb9feb8952b9d6b
2016-02-11 17:16:58 +10:00
David Herrmann
92ffda48ee Merge pull request #2 from whot/master
Add missing attributes.m4
2016-01-16 20:34:42 +01:00
Peter Hutterer
91a4a325ae Add missing attributes.m4
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2015-11-20 09:06:17 +10:00
David Herrmann
7cff5e58f0 Merge pull request #1 from bentiss/master
Add Readme and the policy file required
2015-10-15 11:01:52 +02:00
Benjamin Tissoires
17f0fc41d1 Add Readme and the policy file required
Or running ratbagd (as root) raises a "Permission denied".

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2015-10-14 11:34:27 -04:00
David Herrmann
958e86f67e ratbagctl: pick default device if none given for show-device
Lets use the new get_device_path() helper to allow calling show-device
without any argument. This follows what show-profile does already.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 19:02:12 +02:00
David Herrmann
acb0118897 ratbagctl: split get_profile_path()
Split get_profile_path() and provide an helper for get_device_path() on
its own.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 19:00:27 +02:00
David Herrmann
85a045c538 ratbagctl: move get_profile_path()
Move get_profile_path() up to make it available to other verbs as well.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 18:57:42 +02:00
David Herrmann
fbffe241e6 ratbagctl: add show-profile verb
New verb: show-profile

This simply prints a profile of a given device by querying ratbagd for
all information on the selected profile.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 18:56:25 +02:00
David Herrmann
765fd1565a ratbagd: expose resolutions on the bus
Add a new property to profiles that exposes resolutions on the bus. We
simply expose a dictionary entry for each resolution, hence, we can
easily extend it in the future. However, we avoid the full overhead of
real dbus objects, as there is no real need for it.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 18:55:03 +02:00
David Herrmann
1a677c0b1d ratbagd: add DBus methods to retrieve object paths
Add two new helpers to query ratbagd for the object-paths of a specific
object:
  GetDeviceByName: Return device given a device name
  GetProfileByIndex: Return a profile given a profile index

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 18:53:54 +02:00
David Herrmann
eeb8788413 ratbagctl: print the default profile
Include the default profile in 'show-device' output.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:35:00 +02:00
David Herrmann
c24ca68d63 ratbagd: expose 'DefaultProfile'
Add a new property that exposes the default profile.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:34:32 +02:00
David Herrmann
e189dc3b1f ratbagd: never return ENODATA for Get()
We should always provide valid data if requested via Get().
Unfortunately, DBus still does not include 'maybe' types, so we just
return something that is clearly invalid data.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:33:30 +02:00
David Herrmann
ff8f391e91 ratbagctl: implement list-devices and show-device
Two new verbs for ratbagctl:
 - list-devices: list all available devices
 - show-device: show detailed information about a single device

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
0a9c2824ba ratbagd: expose profile information
Expose a list of profiles, including a tag for the active profile, from
within each ratbagd device via DBus.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
dc37d3bf62 ratbagd: ignore NULL profiles
Never return information about non-existant profiles. Just skip NULL
profiles silently, when iterating.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
2780e6f3d7 ratbagd: simplify profile DBus paths
Refrain from hierarchical paths and instead use object prefixes with
unique paths each. This avoids several nasty DBus-enforced behaviors
regarding deep hierarchies. Furthermore, it keeps the names shorter,
which is always a nice side-effect.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
260df58856 ratbagd: profile profile accessors
Provide two new profile accessors that return the path and index of a
profile. This also requires us to cache the dbus path in the profile
itself.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
cba28a97a0 ratbagd: add ratbagd_device_get_name()
New helper to return the name of a device. This will be required to build
hierarchical paths in the sub-classes, like profiles.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 16:23:51 +02:00
David Herrmann
eca2203603 ratbagd: add manager interface
Instead of relying on the cricket ObjectManager interface, use our own
manager interface. This gets rid of ridiculous recursive behavior of the
ObjectManager interface and instead allows us to control the behavior.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 14:09:23 +02:00
David Herrmann
e926212554 ratbagd: remove ratbagd_device_list()
This is no longer needed. Use the device-iterator in ratbagd.c directly
and then drop ratbagd_device_list().

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 13:25:05 +02:00
David Herrmann
65463b6efb ratbagd: add device iterator
Add iterators for ratbagd_device objects.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 13:22:13 +02:00
David Herrmann
9ac799bc95 ratbagd: add ratbagd_device_get_path()
Add helper to retrieve the device path from outside of ratbagd-device.c.
This will be needed for the non-object-manager based enumerators and
signals introduced to org.freedesktop.ratbag1.Manager.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 13:21:27 +02:00
David Herrmann
7e4d757bdf ratbagd: cache device path
Cache device path in device->path and avoid re-calculating it all the
time.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-29 13:09:45 +02:00
David Herrmann
1a8037cd6c ratbagd: expose profiles on the bus
Profiles are static children of devices. Expose them as 2nd-level objects
underneath their parent devices on the bus.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-26 18:53:55 +02:00
David Herrmann
dbc8a37b56 ratbagd: move dbus device management
Make sure the device management (lookup and enumeration and registration)
is done from the parent, not the child. Hence, move it into ratbagd.c over
ratbagd-device.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-26 18:07:18 +02:00
David Herrmann
b1851ada93 ratbagd: split dbus handling from object handling
Make sure our dbus callbacks to not contain any logic themselves. They
should be simple wrappers around our internal object handling.

This also makes use of the new sd-bus pat helpers, to-be-released with
systemd-v227 next week.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-26 18:02:00 +02:00
David Herrmann
c0799b0c1d ratbagd: drop UNPRIVILEGED from properties
This does not work, we cannot flag properties as UNPRIVILEGED. Drop it.
Lets figure out later what exactly we want as privilege level to
enumerate and query device properties.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-26 17:59:58 +02:00
David Herrmann
e461710811 ratbagd: add basic device properties
Add two device properties:
  - Id: Returns the string ID to identify the device
  - Description: Returns the ratbag-device name

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 16:27:45 +02:00
David Herrmann
bea8e89cc7 ratbagd: create libratbag_device contexts
Make sure to create libratbag_device contexts for each device we add. If
libratbag returns NULL, we just ignore the devices. Otherwise, we keep
the context around and manage the device.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 16:05:26 +02:00
David Herrmann
17d66153b0 ratbagd: ignore anything but event devices
We are only interested in evdev, so ignore anything but input-event
devices.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 15:57:14 +02:00
David Herrmann
8ca0c11154 ratbagd: keep libratbag context around
Make sure the ratbagd context has a reference to a valid libratbag
context at all times. We need this to access libratbag devices, so lets
reference on in our own context.

This also adds a dependency for libratbag via autotools.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 12:51:11 +02:00
David Herrmann
c4afc3d5c0 shared: add safe_close()
Add safe_close() helper that makes close(2) a bit nicer to use. This also
introduces PROTECT_ERRNO, which makes sure a function does not clutter
errno if called.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 12:49:44 +02:00
David Herrmann
c22d51e439 build: be more consistent in variable names
Rename UDEV_* to LIBUDEV_* to be more consistent regarding other
pkg-build dependencies.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-25 12:35:43 +02:00
David Herrmann
aa052ae005 Import initial components
This adds two new components:

1) ratbagd
   The ratbagd daemon is a very basic dbus daemon that provides an
   org.freedesktop.DBus.ObjectManager based enumeration and modification
   API for libratbag devices. So far, all it does is enumerate input
   devices on the bus. However, this will be extended to advertise full
   libratbag hierarchies on the bus and allow clients to modify
   properties via DBus.

   So far, it is root-only, but the DBus policy can be losened and PolKit
   support can be added.

2) ratbagctl
   A very basic command-line tool to manage ratbagd. It's basically a
   command-line interface for the DBus API of ratbagd.

   So far, it has no hookup for anything. This will be added once ratbagd
   gains further DBus APIs.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-24 20:05:27 +02:00
David Herrmann
3f0b41ec3c Initialize ratbagd repository
Initial commit for the ratbagd project, a dbus daemon to manage libratbag
devices and proxy user accesses.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
2015-09-24 16:45:22 +02:00
99 changed files with 18667 additions and 16307 deletions

3
.flake8 Normal file
View File

@@ -0,0 +1,3 @@
[flake8]
ignore = E402,E501
exclude = .git,__pycache__,build,data,piper/piper.py

View File

@@ -1,4 +1,5 @@
Copyright © 2015 Red Hat, Inc.
Copyright © 2015-2017 Red Hat, Inc.
Copyright © 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

303
DBusInterface.md Normal file
View File

@@ -0,0 +1,303 @@
The ratbagd DBus-Interface
--------------------------
Note: **the DBus interface is subject to change**
Interfaces:
- org.freedesktop.ratbag1.Manager
- org.freedesktop.ratbag1.Device
- org.freedesktop.ratbag1.Profile
- org.freedesktop.ratbag1.Resolution
- org.freedesktop.ratbag1.Button
- org.freedesktop.ratbag1.Led
For a list of dbus types as used below, see https://dbus.freedesktop.org/doc/dbus-specification.html
Properties marked as 'constant' do not change for the lifetime of the
object. Properties marked as 'mutable' may change, and a
`org.freedesktop.DBus.Properties.PropertyChanged` signal is sent for those
unless otherwise specified.
org.freedesktop.ratbag1.Manager
===============================
The **org.freedesktop.ratbag1.Manager** interface is the entry point to
interact with ratbagd.
### Properties:
#### `Devices`
- type `ao`, read-only, mutable
Provides the object paths of all current devices, see **org.freedesktop.ratbag1.Device**
#### `Themes`
- type `as`, read-only, constant
Provides the list of available theme names. This list is guaranteed to have
one theme available ('default'). Other themes are implementation defined.
A theme listed here is only a guarantee that the theme is known to libratbag
and that SVGs *may* exist, it is not a guarantee that the SVG for any
specific device exists. In other words, a device may not have an SVG for a
specific theme.
This list is static for the lifetime of ratbagd.
org.freedesktop.ratbag1.Device
==============================
The **org.freedesktop.ratbag1.Device** interface describes a single device
known to ratbagd.
### Properties:
#### `Id`
- type: `s`, read-only, constant
An ID describing this device. This ID should not be used for presentation to
the user.
#### `Description`
- type: `s`, read-only, constant
The device's name, suitable for presentation to the user.
#### `Capabilities`
- type: `au`, read-only, constant
The capabilities supported by this device. see `enum
ratbag_device_capability` in libratbag.h for the list of permissible
capabilities.
#### `Svg`
- type: `s`, read-only, constant
The device's SVG file name, without path.
#### `Profiles`
- type: `ao`, read-only, mutable
This property is mutable if the device supports adding and removing
profiles.
Provides the list of profile paths for all profiles on this device, see
**org.freedesktop.ratbag1.Profile**.
### Methods:
#### `Commit() → ()`
Commits the changes to the device. Changes to the device are batched; they
are not written to the hardware until `Commit()` is invoked.
#### `GetSvg(s) → (s)`
Returns the full path to the SVG for the given theme or an empty string if
none is available. The theme must be one of
**org.freedesktop.ratbag1.Manager.Themes**. The theme 'default' is
guaranteed to be available. ratbagd may return the path to a file that
doesn't exist. This is the case if the device has SVGs available but not for
the given theme.
org.freedesktop.ratbag1.Profile
===============================
### Properties:
#### `Index`
- type: `u`, read-only, constant
The index of this profile
#### `Enabled`
- type: `b`, read-write, mutable
True if this is the profile is enabled, false otherwise.
Note that a disabled profile might not have correct bindings, so it's
a good thing to rebind everything before calling `Commit()` on the
**org.freedesktop.ratbag1.Device**.
#### `Resolutions`
- type: `ao`, read-only, mutable
This property is mutable if the device supports adding and removing
resolutions.
Provides the object paths of all resolutions in this profile, see
**org.freedesktop.ratbag1.Resolution**
#### `Buttons`
- type: `ao`, read-only, constant
Provides the object paths of all buttons in this profile, see
**org.freedesktop.ratbag1.Button**
#### `Leds`
- type: `ao`, read-only, constant
Provides the object paths of all LEDs in this profile, see
**org.freedesktop.ratbag1.Led**
### `IsActive`
- type: `b`, read-only, mutable
True if this is the currently active profile, false otherwise.
Profiles can only be set to active, but never to not active - at least one
profile must be active at all times. This property is read-only, use the
`SetActive()` method to activate a profile.
### Methods:
#### `SetActive() → ()`
Set this profile to be the active profile
org.freedesktop.ratbag1.Resolution
==================================
### Properties:
#### `Index`
- type: `u`, read-only, constant
Index of the resolution
#### `Capabilities`
- type: `au`, read-only, constant
Array of uints with the capabilities enum from libratbag
#### `IsActive`
- type: `b`, read-only, mutable
True if this is the currently active resolution, false otherwise.
Resolutions can only be set to active, but never to not active - at least
one resoultion must be active at all times. This property is read-only, use the
`SetActive()` method to set a resolution as the active resolution.
#### `IsDefault`
- type: `b`, read-only, mutable
True if this is the currently default resolution, false otherwise. If the
device does not have the default resolution capability, this property is
always false.
Resolutions can only be set to default, but never to not default - at least
one resolution must be default at all times. This property is read-only, use the
`SetDefault()` method to set a resolution as the default resolution.
#### `Resolution`
- type: `uu`, read-write, mutable
uint for the x and y resolution assigned to this entry, respectively
#### `ReportRate`
- type: `u`, read-write, mutable
uint for the report rate in Hz assigned to this entry
#### `Maximum`
- type: `u`, read-only, constant
uint for the maximum possible resolution
#### `Minimum`
- type: `u`, read-only, constant
uint for the minimum possible resolution
### Methods:
#### `SetDefault() → () `
Set this resolution to be the default
#### `SetActive() → () `
Set this resolution to be the active one
org.freedesktop.ratbag1.Button
==============================
### Properties:
#### `Index`
- type: `u`, read-only, constant
Index of the button
#### `Type`
- type: `u`, read-only, constant
Enum describing the button physical type. This type is unrelated to the
logical button mapping and serves to easily identify the button on the
device.
#### `ButtonMapping`
- type: `u`, read-write, mutable
uint of the current button mapping (if mapping to button)
#### `SpecialMapping`
- type: `u`, read-write, mutable
Enum describing the current special mapping (if mapped to special)
#### `KeyMapping`
- type: `au`, read-write, mutable
Array of uints, first entry is the keycode, other entries, if any, are
modifiers (if mapped to key)
#### `Macro`
-type: `a(uu)`, read-write, mutable
Array of (type, keycode), where type may be one of
`RATBAG_MACRO_EVENT_KEY_PRESSED` or `RATBAG_MACRO_EVENT_KEY_RELEASED`.
#### `ActionType`
- type: `u`, read-only, mutable
An enum describing the action type of the button, see
ratbag\_button\_get\_action\_type for the list of enums.
This decides which *Mapping* property has a value.
#### `ActionTypes`
- type: `au`, read-only, constant
Array of enum ratbag\_button\_action\_type, possible values for ActionType
on the current device
### Methods:
#### `Disable() → ()`
Disable this button
org.freedesktop.ratbag1.Led
===========================
### Properties:
#### `Index`
- type: `u`, read-only, constant
Index of the LED
#### `Mode`
- type: `u`, read-write, mutable
uint mapping to the mode enum from libratbag
#### `Type`
- type: `u`, read-only, mutable
enum describing the LED type
#### `Color`
- type: `(uuu)`, read-write, mutable
uint triplet (RGB) of the LED's color
#### `EffectRate`
- type: `u`, read-write, mutable
The effect rate in Hz, possible values are in the range 100 - 20000
#### `Brightness`
- type: `u`, read-write, mutable
The brightness of the LED, possible values are in the range 0 - 255
For easier debugging, objects paths are constructed from the device. e.g.
`/org/freedesktop/ratbag/button/event5/p0/b10` is the button interface for
button 10 on profile 0 on event5. The naming is subject to change. Do not
rely on a constructed object path in your application.

View File

@@ -5,18 +5,66 @@ libratbag is a configuration library for gaming mice. It provides a generic
way to access the various features exposed by these mice and abstracts away
hardware-specific and kernel-specific quirks.
Documentation
-------------
libratbag exports the devices over a DBus daemon called **ratbagd**, see the
[ratbagd DBus Interface description](DBusInterface.md).
API documentation is available here:
Compiling libratbag
-------------------
http://libratbag.github.io/libratbag/
libratbag uses the [meson build system](http://mesonbuild.com) which in
turn uses ninja to invoke the compiler. Run the following commands to clone
libratbag and initialize the build:
Architecture
------------
git clone https://github.com/libratbag/libratbag.git
cd libratbag
meson builddir --prefix=/usr/
libratbag has two main components, the front-end API and wrapper code, and
the back-end HW-specific drivers:
And to build or re-build after code-changes, run:
ninja -C builddir
sudo ninja -C builddir install
Note: `builddir` is the build output directory and can be changed to any
other directory name. To set configure-time options, use e.g.
mesonconf builddir -Denable-documentation=false
Run `mesonconf builddir` to list the options.
Running ratbagd as DBus-activated systemd service
-------------------------------------------------
To run ratbagd, simply run it as root `sudo ratbagd`. However,
ratbagd is intended to run as dbus-activated systemd service and installs
the following files:
/usr/share/dbus-1/system.d/org.freedesktop.ratbag1.conf
/usr/share/dbus-1/system-services/org.freedesktop.ratbag1.conf
/usr/share/systemd/system/ratbagd.service
These files are installed into the prefix by `ninja install`, see also the
configure-time options `-Dsystemd-unit-dir` and `-Ddbus-root-dir`.
Developers are encouraged to simply symlink to the files in the git
repository.
For the files to take effect, you should run
sudo systemctl daemon-reload
sudo systemctl reload dbus.service
And finally, to enable the service:
sudo systemctl enable ratbagd.service
This places the required symlink into the systemd directory so that dbus
activation is possible.
libratbag Internal Architecture
-------------------------------
libratbag has two main components, libratbag and ratbagd.
The former is a library to access the devices. It consists of
the front-end API and wrapper code, and the back-end HW-specific drivers:
+-----+ +-----+ +-----------+ +----------+
| app | -> | API | -> | hw-driver | -> | protocol | -> device
@@ -29,8 +77,8 @@ implemented. The HW driver then only accesses the bits required for
libratbag. This allows us to optionally export the protocol as separate
library in the future, if other projects require it.
Adding Devices
--------------
Adding Devices to libratbag
---------------------------
As of commit 3605bede4 libratbag now uses a hwdb entry to match the device
with the drivers. To access a device through libratbag, the udev property
@@ -65,28 +113,6 @@ Source
git clone https://github.com/libratbag/libratbag.git
Building
--------
libratbag uses the meson build system, see http://mesonbuild.com which in
turn uses ninja to invoke the compiler (`ninja` may be `ninja-build` on your
distribution). From a fresh git checkout, run the
following commands to init the repository:
meson builddir --prefix=/usr/
And to build or re-build after code-changes, run:
ninja -C builddir
sudo ninja -C builddir install
Note: 'builddir' is the build output directory and can be changed to any
other directory name. To set configure-time options, use e.g.
mesonconf builddir -Denable-documentation=no
Run 'mesonconf builddir' to list the options.
Bugs
----
@@ -119,4 +145,4 @@ libratbag is licensed under the MIT license.
See the COPYING file for the full license information.
[![Build Status](https://semaphoreci.com/api/v1/projects/7905244a-c0b5-468b-9071-d846de3ce9f1/545192/badge.svg)](https://semaphoreci.com/libratbag/libratbag)
[![Build Status](https://circleci.com/gh/libratbag/libratbag.svg?style=shield&circle-token=d7c782e10d2d934b176da754f11b5105ea074f4a)](https://circleci.com/gh/libratbag/libratbag)

135
circle.yml Normal file
View File

@@ -0,0 +1,135 @@
libratbag_references:
default_settings: &default_settings
working_directory: ~/libratbag
build_default: &build_default
name: Build
command: |
rm -rf build
meson build ${MESON_PARAMS}
mesonconf build
ninja -v -C build ${NINJA_ARGS}
environment:
MESON_PARAMS: --prefix=/usr
build_and_test: &build_and_test
run:
<<: *build_default
name: Build and test
environment:
NINJA_ARGS: test
install: &install
run:
name: Installing
command: ninja -C build install
check_uninstall: &check_uninstall
run:
name: Checking if any files are left after uninstall
command: |
PREFIX=/root/test_install
# workaround until https://github.com/mesonbuild/meson/pull/2033 is merged
# and a new release appears
git clone https://github.com/whot/meson -b wip/remove-directories-on-uninstall
./meson/meson.py build_install --prefix=$PREFIX
ninja -C build_install install
ninja -C build_install uninstall
if [ -d $PREFIX ]
then
tree $PREFIX
exit 1
fi
export_logs: &export_logs
store_artifacts:
path: ~/libratbag/build/meson-logs
ninja_scan_build: &ninja_scan_build
run:
<<: *build_default
name: Ninja scan-build
environment:
NINJA_ARGS: scan-build
start_dbus: &start_dbus
run:
name: Start dbus daemon
command: |
mkdir /run/dbus
/usr/bin/dbus-daemon --system --fork
fedora_install: &fedora_install
run:
name: Install prerequisites
command: dnf install -y tree git gcc gcc-c++ meson check-devel libudev-devel libevdev-devel doxygen graphviz valgrind python3-gobject python3-evdev
fedora_settings: &fedora_settings
<<: *default_settings
steps:
- *fedora_install
- checkout
- *start_dbus
- *build_and_test
- *install
- *check_uninstall
- *export_logs
ubuntu_settings: &ubuntu_settings
<<: *default_settings
steps:
- run:
name: Install prerequisites
command: |
apt-get update
apt-get install -y software-properties-common
add-apt-repository universe
apt-get update
apt-get install -y tree git gcc g++ pkg-config meson check libudev-dev libevdev-dev libsystemd-dev doxygen graphviz valgrind python3-gi python3-evdev
- checkout
- *start_dbus
- *build_and_test
- *install
- *check_uninstall
- *export_logs
scan_build_run: &scan_build_run
<<: *default_settings
steps:
- *fedora_install
- run:
name: Install clang and find
command: dnf install -y clang-analyzer findutils
- checkout
- *ninja_scan_build
- *export_logs
- run:
name: Check scan-build results
command: test ! -d ~/libratbag/build/meson-logs/scanbuild || test $(find ~/libratbag/build/meson-logs/scanbuild -maxdepth 0 ! -empty -exec echo "not empty" \; | wc -l) -eq 0 || (echo "Check scan-build results" && false)
version: 2
jobs:
fedora_rawhide:
<<: *fedora_settings
docker:
- image: fedora:rawhide
fedora_latest:
<<: *fedora_settings
docker:
- image: fedora:latest
ubuntu_17_04:
<<: *ubuntu_settings
docker:
- image: ubuntu:zesty
scan_build:
<<: *scan_build_run
docker:
- image: fedora:latest
workflows:
version: 2
compile_and_test:
jobs:
# - fedora_rawhide
- scan_build
- ubuntu_17_04
- fedora_latest

View File

@@ -1,20 +1,11 @@
libratbag data files
====================
These SVG files should approximate the device to make it immediately
recognizable. Detail work not required, the graphic is an illustration only.
This directory contains the SVG files for each theme. In general, device SVGs
should approximate the device to make it immediately recognizable. Detail work
not required, the graphic is an illustration only.
Requirements
------------
- Canvas size: 750x750 pixels
- Two layers in the final SVG: a lower layer named "Device" with the device
itself, "Leaders" with the buttons and leader-lines
- The device should be approximately centered on the canvas and occupy a
meaningful portion of the canvas without making it look cramped
- Button labels must be in 12pt Sans, starting with Button0
- Wheel buttons may be labeled separately if required (look at the Etekcity
for an example)
For theme-specific requirements, consult the README in the subdirectories.
Technique
---------

15
data/default/README.md Normal file
View File

@@ -0,0 +1,15 @@
libratbag default theme
====================
Requirements
------------
- Canvas size: 750x750 pixels
- Two layers in the final SVG: a lower layer named "Device" with the device
itself, "Leaders" with the buttons and leader-lines
- The device should be approximately centered on the canvas and occupy a
meaningful portion of the canvas without making it look cramped
- Button labels must be in 12pt Sans, starting with Button0
- Wheel buttons may be labeled separately if required (look at the Etekcity
for an example)

436
data/default/etekcity.svg Normal file
View File

@@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
viewBox="0 0 750.00005 750"
height="750"
width="750"
sodipodi:docname="etekcity.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview75"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="0.90533333"
inkscape:cx="249.19702"
inkscape:cy="368.25832"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs4">
<linearGradient
id="linearGradient4449">
<stop
style="stop-color:#a6a6a6;stop-opacity:1"
offset="0"
id="stop4451" />
<stop
style="stop-color:#484848;stop-opacity:1"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
id="linearGradient4336">
<stop
style="stop-color:#898989;stop-opacity:1;"
offset="0"
id="stop4338" />
<stop
style="stop-color:#898989;stop-opacity:0;"
offset="1"
id="stop4340" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4449"
id="linearGradient3237-3-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5735897,0,0,1.5735897,515.00096,570.33442)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
y2="29.577879"
x2="31.968746"
y1="18.546629"
x1="31.968746"
gradientTransform="matrix(1.5735898,0,0,-1.5735898,515.00096,691.37898)"
gradientUnits="userSpaceOnUse"
id="linearGradient4593-2-5"
xlink:href="#linearGradient4449" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4336"
id="linearGradient4784"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79176032,0,0,0.79176032,-529.7793,277.79557)"
x1="97.085503"
y1="74.08123"
x2="95.471596"
y2="200.83122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4786"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-441.46063,314.40367)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Device">
<g
transform="matrix(1.0968619,0,0,1.0968619,-53.374562,-35.91136)"
style="display:inline;stroke-width:0.91169178"
id="layer6">
<g
id="layer2-9"
style="display:inline;stroke-width:0.91169178"
transform="translate(-0.549249,-6.732224)">
<g
style="display:inline;stroke-width:0.91169178"
transform="matrix(1.066667,0,0,1.066667,706.52353,-41.851899)"
id="layer5">
<g
style="display:inline;stroke-width:0.91169178"
transform="translate(102.62379,-59.6133)"
id="g3893">
<g
id="g4271"
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.91169178"
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,192.05523)">
<path
inkscape:connector-curvature="0"
id="path4249"
d="m 421.23361,409.14757 c 4.4349,4.09496 9.16721,10.86185 32.57742,27.27412 4.08118,24.47294 2.40765,48.35999 1.01015,67.42768 -1.3975,19.06769 -9.52288,85.7367 -30.55711,85.7367 l -41.92133,-6.18719 8.9651,-171.72593 32.38801,-150.26019 27.05315,-2.27284 -2.70689,27.21098 -26.19294,53.47495 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,580.95786,0)"
id="use4266"
xlink:href="#path4249"
y="0"
x="0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.91169178" />
</g>
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.91169178px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -268.43146,403.53037 c -1.07689,19.01234 -1.64984,38.40264 -3.69907,56.68573 -2.36798,4.75208 -4.96718,7.8857 -7.59809,10.79728 h -13.59657 l 5.59859,-67.18309 z"
id="path4251" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.91169178px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -281.12826,473.7127 -0.29993,6.19844 7.09822,5.79854 -2.19945,30.1924 -8.99773,9.59758 -0.29993,28.99271 -2.3994,3.59909 h -14.59632 v -84.47873 z"
id="path4253" />
<use
style="display:inline;stroke-width:0.91169178"
x="0"
y="0"
xlink:href="#path4251"
id="use4275"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
width="1469.2054"
height="1013.322" />
<ellipse
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,124.43258)"
style="display:inline;fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1.15147448;stroke-opacity:1"
id="path4243"
cx="290.47894"
cy="231.07376"
rx="57.5"
ry="36.875" />
<use
style="display:inline;stroke-width:0.91169178"
x="0"
y="0"
xlink:href="#path4253"
id="use4277"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
width="1469.2054"
height="1013.322" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#282828;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.91169178px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -401.08313,328.79009 0.26444,-40.70143 c -39.18883,7.37119 -44.1411,4.0242 -51.69484,0.84743 -19.57977,14.34842 -45.06471,30.13362 -73.61979,38.63234 -2.47282,19.58198 -2.71663,46.75085 -2.09075,66.56663 19.0204,10.56139 17.6053,33.92046 19.25741,48.34377 1.65211,14.4233 7.20626,94.24576 7.20626,94.24576 l -2.59797,21.72393 23.30745,43.04888 c -0.16213,7.00604 -0.46719,14.87323 -3.03251,37.40758 -7.15647,2.04323 -13.81042,1.56652 -20.02442,-1.10259 0.0912,10.91499 -0.68305,21.82736 0.56908,32.68021 11.24444,13.4205 16.39645,27.09393 56.20571,56.18715 l 6.498,11.63207 c 13.0739,7.46592 23.16933,11.65186 42.40866,14.95221 19.23933,-3.30035 29.33476,-7.48629 42.40866,-14.95221 l 6.498,-11.63207 c 39.80926,-29.09322 44.96127,-42.76665 56.2057,-56.18715 1.25213,-10.85285 0.47635,-21.76522 0.56754,-32.68021 -6.214,2.66911 -12.86641,3.14582 -20.02288,1.10259 -2.56532,-22.53435 -2.87037,-30.40154 -3.0325,-37.40758 l 23.3059,-43.04888 -2.59642,-21.72393 c 0,0 5.55415,-79.82246 7.20625,-94.24576 1.65211,-14.42331 0.23546,-37.78238 19.25586,-48.34377 0.62589,-19.81578 0.38362,-46.98465 -2.08919,-66.56663 -28.55509,-8.49872 -54.04157,-24.28392 -73.62134,-38.63234 -7.55373,3.17677 -12.50447,6.52376 -51.69329,-0.84743 l 0.26444,40.70143 z"
id="path3441" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:none;stroke:#ff0000;stroke-width:0.91169178px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -398.45459,328.52925 V 446.37959"
id="path4289" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.91169178px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -390.51793,495.35976 13.14911,20.077 h 24.31724 l -19.22802,-64.1898 -26.14665,-13.56354 -26.14819,13.56354 -19.22802,64.1898 h 24.31879 l 13.14909,-20.077 z"
id="path4247" />
<rect
style="display:inline;fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:0.91169178;stroke-opacity:1"
id="rect4245"
width="25.025282"
height="59.523411"
x="-410.93967"
y="334.18024"
rx="3.2500002"
ry="3.2500002" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4784);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -408.76059,297.49061 c -14.10207,2.39851 -28.95919,4.88556 -42.94836,0.51186 -20.52977,14.9081 -42.9383,27.51676 -67.08004,35.5287 -1.79569,18.70085 -2.21232,37.56904 -1.4629,56.27529 14.36611,10.46486 18.14376,29.44442 18.67596,46.17572 1.42879,19.10333 3.31403,38.21183 4.78767,57.33922 l 94.06329,0.0603 v -99.67829 h -5.64129 c -1.42556,0 -2.57322,-1.14766 -2.57322,-2.57323 v -54.37631 c 0,-1.42556 1.14766,-2.57322 2.57322,-2.57322 h 2.21136 c -2.89117,-5.43908 -2.75569,-17.98166 -2.75569,-23.06002 0,-6.57742 0.14421,-9.08623 0.15,-13.63002 z"
id="path4311" />
<use
style="display:inline;stroke-width:0.91169178"
x="0"
y="0"
xlink:href="#path4311"
id="use4348"
transform="matrix(-1,0,0,1,-796.64968,2.010815e-6)"
width="1469.2054"
height="1013.322" />
<circle
transform="matrix(0.79176032,0,0,0.79176032,-529.7793,210.17291)"
style="display:inline;fill:#898989;fill-opacity:1;stroke:none;stroke-width:0.91169178"
id="path4352"
cx="165.89903"
cy="194.21156"
r="13.13577" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -420.59834,454.5406 c -5.60675,18.71514 -11.21351,37.43027 -16.82027,56.1454 5.1217,0 10.2434,0 15.3651,0 4.38485,-6.69216 8.76766,-13.38566 13.15375,-20.077 6.98254,0 13.96508,0 20.94762,0 4.38609,6.69134 8.76889,13.38484 13.15374,20.077 5.12118,0 10.24237,0 15.36355,0 -5.60676,-18.71565 -11.21352,-37.43129 -16.82027,-56.14694 -7.39028,-3.83406 -14.78056,-7.66812 -22.17083,-11.50218 -7.39079,3.83457 -14.78159,7.66915 -22.17239,11.50372 z"
id="path4357" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -521.43644,406.56488 c -1.77374,0.0227 -3.15566,0.4222 -3.55518,1.76754 l 0.11752,2.1727 c 1.24058,16.62081 0.75876,33.65011 3.93561,49.99997 1.98359,2.87617 3.63732,8.09685 7.96709,7.20935 1.8046,-0.22471 4.69928,1.07511 6.16243,-0.0881 -0.0876,-1.12531 -0.18047,-2.37689 -0.26598,-3.46086 -1.38363,-12.51596 -2.3414,-25.11574 -3.33096,-37.70913 -0.77697,-6.57243 -2.15369,-13.39954 -5.30263,-19.41823 -1.9185,-0.16721 -4.00601,-0.49523 -5.7279,-0.4732 z"
id="use4396" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -506.09917,476.83515 c -1.97837,0.009 -3.95674,0.0188 -5.93511,0.0279 0.85216,4.85149 -4.04309,7.59388 -6.85213,10.37484 -0.6345,6.02214 1.09923,12.03757 0.98197,18.13626 0.3064,4.54843 -0.35793,10.2138 4.18921,12.95425 3.89072,2.9778 6.76537,7.60716 5.65521,12.64652 0.43285,7.84497 -0.8119,15.99277 0.9062,23.38167 1.01515,0.57035 2.08809,0.77358 3.18869,0.80413 l 2.20518,-18.43626 c 0,0 -2.26899,-32.57611 -4.33922,-59.88925 z"
id="use4398" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -271.77677,406.75044 c -3.09643,0.0485 -6.19285,0.0969 -9.28928,0.14537 -3.15953,5.97283 -4.55856,12.75131 -5.34747,19.29452 l -3.45931,41.48855 c 3.94759,0.0294 9.07538,1.78551 11.24547,-2.81911 5.80456,-6.57393 3.74439,-15.87475 4.98871,-23.78837 0.76732,-11.43639 1.23856,-22.86533 1.86188,-34.32096 z"
id="path4404" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.91169178"
d="m -288.21508,476.67123 c -0.84134,0.006 -1.68687,0.0599 -2.53457,0.11907 -2.07117,27.32261 -4.3423,59.9341 -4.3423,59.9341 l 2.20826,18.47337 c 1.29581,-0.023 2.52331,-0.3133 3.58612,-1.2263 1.08603,-9.86486 -0.19804,-20.31797 0.95414,-30.09153 3.59307,-4.65204 10.46727,-8.17451 9.15627,-15.08365 0.31411,-7.28513 1.50719,-14.93066 1.3129,-22.00692 -3.27092,-2.21915 -7.90201,-5.21182 -6.84904,-9.77793 -1.14795,-0.27038 -2.31544,-0.34912 -3.49178,-0.34021 z"
id="path4406" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4786);fill-opacity:1;stroke:none;stroke-width:0.91169178"
d="m -398.42702,334.8881 -2.54284,4.40528 -2.54281,4.40266 h 2.90008 v 9.31229 l 2.18557,-1.2609 2.18556,1.2609 v -9.31229 h 2.90008 l -2.54283,-4.40266 z"
id="path4441" />
<use
style="display:inline;stroke-width:0.91169178"
x="0"
y="0"
xlink:href="#path4441"
id="use4460"
transform="matrix(1,0,0,-1,-9.1690072e-7,727.78645)"
width="1469.2054"
height="1013.322" />
</g>
</g>
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Leaders">
<path
id="path4211"
d="M 292.70532,245.09234 251.78243,107.31863"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4215"
d="M 459.12507,234.17958 530.45112,110.63926"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4227"
d="m 136.73079,278.9931 99.36454,68.40648"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4229"
d="M 134.68465,353.33635 242.9158,425.83512"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4546"
d="M 373.8779,389.96445 480.48362,283.35873 h 88.33698"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4221"
d="M 568.78,356.23193 H 511.64278"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
id="path4225"
d="M 568.89967,423.74332 H 509.44904"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient3237-3-3);fill-opacity:1;stroke:none;stroke-width:1.06666708"
d="m 565.3497,594.30093 -2.97509,5.1541 -2.97505,5.15104 h 3.39305 v 10.89527 l 2.55709,-1.47523 2.55708,1.47523 v -10.89527 h 3.39306 l -2.97509,-5.15104 z"
id="path4556"
inkscape:connector-curvature="0" />
<path
id="use4558"
d="m 565.3497,667.41248 -2.97509,-5.15413 -2.97505,-5.15105 h 3.39305 v -10.89527 l 2.55709,1.47523 2.55708,-1.47523 v 10.89527 h 3.39305 l -2.97508,5.15105 z"
style="display:inline;fill:url(#linearGradient4593-2-5);fill-opacity:1;stroke:none;stroke-width:1.06666708"
inkscape:connector-curvature="0" />
<text
id="text4473"
y="92.597137"
x="200.24596"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4217"
y="92.597137"
x="200.24596">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
x="519.96796"
y="103.0135"
id="text4477"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4479"
x="519.96796"
y="103.0135">Button1</tspan></text>
<text
id="text4481"
y="36.971676"
x="375.0303"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
y="36.971676"
x="375.0303"
id="tspan4483">Button2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
x="81.078667"
y="268.62354"
id="text4485"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4487"
x="81.078667"
y="268.62354">Button3</tspan></text>
<text
id="text4489"
y="347.68259"
x="77.313698"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
y="347.68259"
x="77.313698"
id="tspan4491">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
x="571.02142"
y="290.06454"
id="text4493"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4495"
x="571.02142"
y="290.06454">Button5</tspan></text>
<text
id="text4497"
y="359.25067"
x="580.3692"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
y="359.25067"
x="580.3692"
id="tspan4499">Button6</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
x="574.50854"
y="428.69608"
id="text4501"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4503"
x="574.50854"
y="428.69608">Button7</tspan></text>
<text
id="text4505"
y="613.29852"
x="584.23242"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
y="613.29852"
x="584.23242"
id="tspan4507">Button8</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666708"
x="584.95984"
y="662.38556"
id="text4509"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.54979134px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666708"
id="tspan4511"
x="584.95984"
y="662.38556">Button9</tspan></text>
<path
id="path4213"
d="m 374.55111,266.91789 h 30.01011 V 45.934283"
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -0,0 +1,754 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg8"
version="1.1"
viewBox="0 0 198.4375 198.43751"
height="750"
width="750"
sodipodi:docname="logitech-g300.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview127"
showgrid="false"
inkscape:zoom="0.90533333"
inkscape:cx="375"
inkscape:cy="375"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs2">
<linearGradient
id="linearGradient7649">
<stop
style="stop-color:#f5f5f5;stop-opacity:1"
offset="0"
id="stop7643" />
<stop
id="stop7645"
offset="0.42190266"
style="stop-color:#030303;stop-opacity:1" />
<stop
style="stop-color:#ededed;stop-opacity:1"
offset="1"
id="stop7647" />
</linearGradient>
<linearGradient
id="linearGradient5366-6">
<stop
id="stop5360"
offset="0"
style="stop-color:#f5f5f5;stop-opacity:1" />
<stop
style="stop-color:#030303;stop-opacity:1"
offset="0.51176381"
id="stop5362" />
<stop
id="stop5364"
offset="1"
style="stop-color:#ededed;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4649">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4645" />
<stop
id="stop4651"
offset="0.49026167"
style="stop-color:#a2a2a2;stop-opacity:1" />
<stop
style="stop-color:#000000;stop-opacity:1"
offset="1"
id="stop4647" />
</linearGradient>
<linearGradient
id="linearGradient4581-3">
<stop
id="stop4577"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop4579"
offset="1"
style="stop-color:#ececec;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="43.886501"
x2="111.31824"
y1="50.580582"
x1="106.2162"
id="linearGradient6815-1"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="35.112171"
x2="100.22734"
y1="42.556988"
x1="96.357521"
id="linearGradient6645-6"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="73.771301"
x2="50.455471"
y1="83.415108"
x1="40.34473"
id="linearGradient5376-4"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="71.838379"
x2="45.254807"
y1="76.173668"
x1="35.011879"
id="linearGradient5354-5"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
y2="67.095848"
x2="91.018227"
y1="75.713417"
x1="82.07766"
gradientTransform="matrix(1.1187372,0,0,1.1567117,-4.7672285,-6.6331718)"
gradientUnits="userSpaceOnUse"
id="linearGradient5326-4"
xlink:href="#linearGradient5366-6" />
<linearGradient
gradientTransform="matrix(0.99489774,0,0,1.0286686,19.795332,9.3182056)"
y2="64.980942"
x2="82.750046"
y1="75.018211"
x1="84.70034"
gradientUnits="userSpaceOnUse"
id="linearGradient5320-4"
xlink:href="#linearGradient4581-3" />
<linearGradient
y2="63.717323"
x2="77.788185"
y1="73.272537"
x1="79.893219"
gradientUnits="userSpaceOnUse"
id="linearGradient5336-7"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.07419,15.177773)"
gradientUnits="userSpaceOnUse"
y2="43.694389"
x2="69.186096"
y1="185.06635"
x1="148.15651"
id="linearGradient4583-3"
xlink:href="#linearGradient4581-3" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="151.89273"
x2="35.842487"
y1="116.10757"
x1="78.975082"
id="linearGradient4608-6"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="105.68479"
x2="160.22058"
y1="113.20518"
x1="149.38902"
id="linearGradient4597-8"
xlink:href="#linearGradient4581-3"
gradientTransform="matrix(0.88930424,0,0,0.88930424,24.034848,15.217114)" />
<linearGradient
gradientTransform="translate(5.7351308,-2.1927033)"
y2="57.257454"
x2="79.269432"
y1="64.032951"
x1="70.218117"
gradientUnits="userSpaceOnUse"
id="linearGradient9255"
xlink:href="#linearGradient4649" />
<linearGradient
gradientTransform="translate(5.7351308,-2.1927033)"
y2="67.40316"
x2="91.913757"
y1="75.838074"
x1="83.709564"
gradientUnits="userSpaceOnUse"
id="linearGradient9257"
xlink:href="#linearGradient5366-6" />
<linearGradient
y2="76.867943"
x2="49.128342"
y1="84.263214"
x1="40.247364"
gradientTransform="translate(5.6466558,-1.9272773)"
gradientUnits="userSpaceOnUse"
id="linearGradient9259"
xlink:href="#linearGradient7649" />
<linearGradient
gradientTransform="translate(5.7351308,-2.1927033)"
y2="34.04863"
x2="99.476608"
y1="44.193058"
x1="95.572289"
gradientUnits="userSpaceOnUse"
id="linearGradient9261"
xlink:href="#linearGradient5366-6" />
<linearGradient
gradientTransform="translate(5.7351308,-2.1927033)"
y2="43.886501"
x2="111.31824"
y1="50.580582"
x1="106.2162"
gradientUnits="userSpaceOnUse"
id="linearGradient9263"
xlink:href="#linearGradient5366-6" />
<filter
height="1.2728308"
y="-0.13641544"
width="1.1993906"
x="-0.09969531"
id="filter5257-2-0"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur5259-0-3"
stdDeviation="0.67565569" />
</filter>
<filter
height="1.0871989"
y="-0.043599416"
width="1.0766768"
x="-0.038338386"
id="filter8545-8-0"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur8547-4-9"
stdDeviation="1.1009866" />
</filter>
<filter
height="1.0289921"
y="-0.014496"
width="1.0568471"
x="-0.028423529"
id="filter8931-8-2"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur8933-6-5"
stdDeviation="0.45344554" />
</filter>
<filter
height="1.1508775"
y="-0.075438753"
width="1.1029657"
x="-0.05148283"
id="filter6058-3-9"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur6060-0-4"
stdDeviation="0.210429" />
</filter>
<filter
height="1.2033294"
y="-0.10166474"
width="1.1502416"
x="-0.075120777"
id="filter6114-7-6"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur6116-4-9"
stdDeviation="0.36423808" />
</filter>
<linearGradient
y2="66.854225"
x2="48.142838"
y1="77.964264"
x1="30.665777"
gradientTransform="matrix(0.70966437,0,0,0.65096738,8.52826,24.237011)"
gradientUnits="userSpaceOnUse"
id="linearGradient9265-2"
xlink:href="#linearGradient5366-6" />
<filter
height="1.3214939"
y="-0.16074698"
width="1.2348779"
x="-0.11743895"
id="filter7639-5-2"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur7641-2-4"
stdDeviation="0.487782" />
</filter>
<filter
height="1.2302096"
y="-0.11510481"
width="1.1831484"
x="-0.091574177"
id="filter7247-3-4"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur7249-7-8"
stdDeviation="0.41036213" />
</filter>
<filter
height="1.2783537"
y="-0.13917683"
width="1.1930734"
x="-0.096536696"
id="filter8043-4-1"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur8045-7-2"
stdDeviation="0.40736955" />
</filter>
<filter
height="1.2202032"
y="-0.11010158"
width="1.1900181"
x="-0.095008977"
id="filter7107-0-8"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
id="feGaussianBlur7109-6-9"
stdDeviation="0.60580599" />
</filter>
<marker
style="overflow:visible"
id="Arrow2Mstart-3"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path9385-6" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker9769-8"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path9767-0"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker10285-2"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path10283-1" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker10813-0"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path10811-5"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker11197-1"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path11195-1" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker11803-0"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11801-8"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker12601-5"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path12599-0" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker13567-6"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path13565-4"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker14005-6"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path14003-2" />
</marker>
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Device">
<g
transform="translate(-3.0873728,3.6519886)"
style="display:inline"
id="layer8">
<path
inkscape:connector-curvature="0"
id="path4589-9"
d="m 149.10287,101.50117 c 0,0 -1.05786,0.16638 4.0148,1.53332 5.07266,1.36693 10.15226,5.82516 11.98533,8.1296 2.51392,2.40918 6.52051,10.23903 1.3879,14.00992 -5.13261,3.7709 -17.38803,-23.67284 -17.38803,-23.67284 z"
style="display:inline;fill:url(#linearGradient4597-8);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4586-2"
d="m 47.656799,72.245042 c 1.942356,-3.777983 8.589985,-9.41686 13.813269,-13.065406 1.567266,-1.09476 3.79326,0.642353 5.704413,0.594209 1.127681,-0.0284 10.73636,-5.504113 11.017493,-6.243426 0.368443,-0.968912 -1.255371,-2.707871 -0.294117,-3.095862 6.37104,-2.571549 13.117079,-5.313039 20.888587,-5.872484 7.771506,-0.559444 17.767586,3.500592 25.075636,9.269673 10.30308,8.133397 18.06398,20.559662 27.69019,44.80342 9.6262,24.243764 12.77467,23.651204 14.20078,23.532374 1.4261,-0.11884 3.83901,-6.01224 -1.15235,-11.47896 -4.99136,-5.46674 -10.07738,-7.18089 -10.07738,-7.18089 0,0 17.91418,5.69939 18.50838,29.46779 0.59422,23.76838 -8.00245,28.28016 -12.54438,31.28987 -6.51013,4.31394 -4.71386,3.59056 -17.00662,9.69133 -15.94321,7.91246 -51.426816,-6.03833 -58.795018,-14.4761 -7.368201,-8.43778 -3.725533,-14.73474 -8.122685,-26.2624 -4.397154,-11.52768 -20.55966,-35.414905 -20.55966,-35.414905 0,0 -7.654168,-11.693722 -9.136414,-18.370041 -0.343475,-1.547078 -1.15248,-3.410207 0.789876,-7.188192 z"
style="display:inline;opacity:1;fill:#050501;fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4600-6"
d="m 103.98404,157.58344 c 5.34109,-2.28109 8.14446,-5.10628 7.17707,-8.95743 C 108.41973,137.71258 96.185717,130.62094 87.905188,122.36574 76.932121,111.42625 56.762426,97.598091 53.011756,91.654563 c 5.289391,8.443197 17.264869,25.694437 21.193431,34.101017 3.92856,8.40659 5.326392,10.83456 7.357476,22.20279 2.031081,11.36824 13.649194,13.51119 22.421377,9.62507 z"
style="display:inline;fill:url(#linearGradient4608-6);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
id="path4630-6"
d="m 71.205713,51.477546 c 1.791534,-0.716614 4.879796,-1.532756 8.88373,1.532757 4.003934,3.065513 5.458341,4.46734 5.067478,6.037182 -0.436294,1.752311 -4.660828,4.035215 -7.413534,3.597284 -2.752704,-0.43793 -8.10171,-4.348022 -8.602201,-6.162304 -0.500494,-1.814282 -0.06576,-4.152802 2.064527,-5.004919 z"
style="display:inline;fill:url(#linearGradient9255);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5257-2-0)" />
<path
inkscape:connector-curvature="0"
style="display:inline;opacity:1;fill:url(#linearGradient4583-3);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 129.57912,64.421701 c -4.02561,0.627933 -7.50264,0.19394 -8.2263,-0.188069 -1.94545,-1.026962 -3.22816,-2.689304 -5.06731,-4.939595 -1.10426,-1.351113 -2.69039,-2.790981 -3.85765,-3.578251 -4.13658,-2.789973 -7.8692,-2.240708 -9.34964,-3.598119 -1.94376,-2.24103 2.30053,-6.127193 0.76519,-6.334074 -8.32641,-1.121952 -20.979676,3.315328 -22.783881,4.987519 -1.113028,1.031586 0.668263,4.430866 0.719191,5.697487 0.02332,0.580255 -1.705527,1.631637 -4.074122,2.882151 0.39358,0.162424 1.963716,1.31009 4.273294,3.132684 1.867629,-0.936312 4.414217,-0.433059 6.027162,0.154724 1.612943,0.587782 3.57968,1.73307 5.57957,3.798942 1.746528,1.804149 2.745617,3.586443 -0.372413,5.404756 1.010513,0.879362 2.037503,1.783111 3.070206,2.703609 2.578615,-1.314173 4.364533,-1.85557 5.641363,-0.707269 1.8246,1.640927 6.60886,6.409596 8.33059,8.081954 1.48441,1.44184 1.21288,3.210236 -1.31383,4.690652 3.82651,3.99094 6.90726,7.688805 8.37744,10.479682 0.13647,0.259046 -0.30588,0.242884 -0.38261,0.131916 -2.31626,-3.349976 -5.31611,-6.868647 -8.63094,-10.352564 -3.10741,2.202274 -5.34212,1.300996 -6.76368,-0.08526 -1.757879,-1.714218 -6.204391,-5.920059 -7.999085,-7.549923 -1.020934,-0.927168 -1.8553,-2.63953 2.172742,-4.305226 -1.095093,-0.962247 -2.148632,-1.91287 -3.209145,-2.816149 -1.193148,0.947677 -4.702692,1.417889 -6.165911,0.59061 -1.625289,-0.91891 -4.270282,-2.809047 -5.46815,-3.763177 -1.267292,-1.009429 -2.167667,-4.180695 0.275401,-6.048903 -2.488867,-1.9263 -4.051939,-3.072117 -4.148205,-3.138823 -0.825302,0.417497 -3.558598,1.774096 -4.587447,2.30064 -1.503726,0.769578 -4.317148,-0.128829 -5.848823,-0.433786 -1.905003,-0.379286 -4.371397,-0.893915 -5.171614,-0.541384 -2.942512,1.296312 -6.074862,4.787062 -8.627105,7.278119 -2.27056,2.216124 -3.521763,3.746314 -3.736697,6.714802 -0.0876,1.210002 9.706223,-0.641827 10.471747,1.794503 0.36497,1.161541 1.709726,4.925493 2.760199,6.256188 1.025689,1.2993 6.656463,5.179118 9.561507,7.524861 2.055757,1.659965 -2.9966,6.803736 -1.497747,7.784044 17.995826,11.769988 32.861033,21.509038 46.998083,34.211858 4.61386,4.14577 8.60721,8.94008 12.57325,13.71822 3.6281,3.8645 8.87124,2.06461 13.42541,0.24678 4.55417,-1.81783 9.50566,-5.04099 12.09212,-10.05164 1.09196,-4.90777 -0.92741,-9.90219 -2.05352,-14.73013 -2.66586,-11.42928 -6.6914,-22.533831 -11.06818,-33.423235 -2.55172,-6.348681 -6.66426,-14.637972 -8.82766,-18.531751 -2.16338,-3.89378 -2.18061,-4.119987 -3.8828,-5.44937 z"
id="path3770-4" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
id="path8359-9"
d="m 40.682868,81.757779 c 3.273586,5.750891 24.13353,21.123631 33.089756,28.400561 25.480883,20.70322 25.657831,20.88018 35.832486,32.20501 C 102.5271,133.51581 92.647763,123.86601 76.072982,110.51225 59.4982,97.15848 51.445211,93.523393 40.682868,81.757779 Z"
style="display:inline;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter8545-8-0)" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
id="path8549-5"
d="m 129.82819,55.373092 c -2.58325,-3.826262 -5.14432,-6.939375 -7.56369,-9.475619 -2.28354,-2.393862 -3.98129,-3.804147 -3.98129,-3.804147 0,0 1.65448,1.460826 3.88456,3.894587 2.38121,2.598695 4.8504,5.697508 7.4408,9.533472 3.54891,5.255969 6.40972,10.684166 8.63649,15.530661 1.81559,3.951587 4.40778,10.574633 7.03637,17.434214 1.93022,5.037132 3.49502,9.128949 5.15642,13.3596 2.21222,5.63347 3.94334,9.56558 3.94334,9.56558 0,0 -1.64429,-3.96377 -3.7867,-9.62597 -1.4885,-3.934163 -3.25603,-8.671722 -5.06561,-13.394034 -2.6288,-6.860149 -5.22395,-13.490882 -7.04302,-17.450028 -2.23109,-4.855899 -5.09901,-10.297918 -8.65767,-15.568316 z"
style="display:inline;fill:#ffffff;fill-rule:nonzero;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter8931-8-2)" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient5336-7);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 97.053387,81.615705 c 0,0 5.472913,-3.257201 6.423383,-3.887711 0.203,-0.596085 0.15434,-0.700778 0.30827,-1.223197 -0.58011,-0.541244 -1.8937,-1.724806 -2.70251,-2.395301 -0.46484,-0.385345 -1.04865,-0.369782 -1.82756,-0.147241 -0.778907,0.222548 -2.622613,0.958746 -3.727624,1.780359 -0.522664,0.38862 -1.358448,3.035358 -1.045328,3.413581 1.125243,1.359188 2.571369,2.45951 2.571369,2.45951 z"
id="path5296-0" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
id="path5278-4"
d="m 88.506185,70.391657 6.906011,-3.667918 c 0,0 -1.40906,-1.457741 -2.873019,-2.671336 -0.522702,-0.433311 -1.345071,-0.437931 -2.220932,-0.187686 -0.875861,0.250246 -2.949063,1.078084 -4.191619,2.001967 -0.587723,0.436992 -0.664906,1.2013 -0.312809,1.626601 1.265305,1.528374 2.692368,2.898372 2.692368,2.898372 z"
style="display:inline;fill:url(#linearGradient9257);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter6058-3-9)" />
<path
inkscape:connector-curvature="0"
id="path5318-8"
d="m 104.5717,87.70787 c 1.74059,0.303403 4.4547,-1.31763 5.32227,-2.271515 0.48844,-0.537038 0.18246,-2.498079 -0.0446,-3.083973 -0.32583,-0.84082 -2.70273,-3.386009 -3.60759,-4.161578 -0.52003,-0.445733 -1.72952,-0.344279 -2.60091,-0.08686 -0.8714,0.257421 -3.12875,1.665353 -4.364962,2.615721 -0.584724,0.449522 -1.019022,2.120132 -0.66872,2.557623 1.258848,1.572192 3.832542,4.058955 5.964492,4.43058 z"
style="display:inline;fill:url(#linearGradient5320-4);fill-opacity:1;stroke:none;stroke-width:0.26766366px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.85398815,0,0,0.85065967,27.22295,18.060489)"
style="display:inline;fill:url(#linearGradient5326-4);fill-opacity:1;stroke:none;stroke-width:0.30098099px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter6114-7-6)"
d="m 89.122725,78.448498 c 2.074321,1.469692 5.596417,-0.677646 6.766776,-2.178891 1.170358,-1.501246 -2.030052,-4.474198 -3.449872,-5.457294 -1.898288,-1.314392 -4.503703,0.444651 -5.768422,1.404729 -0.657508,0.505474 -2.665663,1.436447 -2.05057,2.215942 2.274973,2.372244 2.427767,2.545822 4.502088,4.015514 z"
id="path5322-7" />
<path
inkscape:connector-curvature="0"
id="path5338-1"
d="m 50.157089,76.970875 c 0.550769,1.967036 4.406159,8.025506 5.507701,8.261554 1.101541,0.236041 4.956931,-1.57363 5.271657,-2.203085 0.314726,-0.629451 -1.337585,-5.58638 -2.596488,-6.687919 -1.258902,-1.10154 -8.654959,-0.39341 -8.18287,0.62945 z"
style="display:inline;fill:url(#linearGradient5354-5);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.85287128,0,0,0.84325571,25.137301,18.710901)"
style="display:inline;fill:url(#linearGradient9265-2);fill-opacity:1;stroke:none;stroke-width:0.17983267px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter7639-5-2)"
d="m 30.96635,68.909681 c 0.439514,1.439863 3.781539,6.228542 4.660569,6.401327 0.879029,0.172783 5.017331,-1.328841 5.268482,-1.789598 0.251151,-0.460756 -1.509768,-4.266162 -2.514372,-5.072484 -1.004603,-0.806324 -7.791405,-0.287974 -7.414679,0.460755 z"
id="path5356-7" />
<path
inkscape:connector-curvature="0"
id="path5368-2"
d="m 56.608968,86.648691 c 2.989894,3.304623 11.566172,11.487492 12.667713,11.330131 1.101538,-0.157363 2.832531,-4.327479 2.596486,-6.058474 -0.236044,-1.73099 -10.149905,-8.733638 -10.700675,-8.418915 -0.550771,0.314727 -4.406161,2.20308 -4.563524,3.147258 z"
style="display:inline;opacity:1;fill:url(#linearGradient5376-4);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
style="display:inline;fill:url(#linearGradient9259);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter7247-3-4)"
d="m 44.773741,76.938558 c 4.034828,3.618886 10.678674,13.084069 11.917329,12.907119 1.238652,-0.176951 -1.03912,-9.347722 -1.341852,-9.671101 -0.806336,-0.861329 -7.3229,-5.671771 -7.942226,-5.31787 -0.619328,0.353901 -3.434524,1.363181 -2.633251,2.081852 z"
id="path5378-7" />
<path
inkscape:connector-curvature="0"
id="path6637-2"
d="m 105.26368,45.64344 c 2.83744,-0.222544 12.75903,5.610037 11.73921,6.286889 -1.26669,0.840713 -3.82162,2.985881 -4.50651,2.614899 -4.0058,-2.169811 -8.93308,-1.938998 -9.13998,-3.167128 -0.2069,-1.228129 0.73892,-5.345207 1.90728,-5.73466 z"
style="display:inline;fill:url(#linearGradient6645-6);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
style="display:inline;fill:url(#linearGradient9261);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter8043-4-1)"
d="m 97.700498,32.490138 c 3.066172,0.574471 9.403852,4.394314 8.383242,5.317726 -1.31379,1.188668 -1.16927,2.043757 -1.93941,1.626597 -4.504426,-2.439897 -6.166216,-0.866562 -6.398866,-2.247563 -0.232651,-1.381 -0.341868,-2.321618 -0.170093,-3.695777 z"
id="path6647-2" />
<path
inkscape:connector-curvature="0"
id="path6807-6"
d="m 113.68441,54.868923 c 0.46393,-0.382114 3.70382,-2.910924 4.31772,-2.487335 0.61389,0.42359 8.53125,6.90077 10.74,10.564704 1.28208,2.126748 -6.39815,1.223998 -7.28834,0.611998 -0.89017,-0.611996 -8.87722,-7.776899 -7.76938,-8.689367 z"
style="display:inline;fill:url(#linearGradient6815-1);fill-opacity:1;stroke:none;stroke-width:0.23529507px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
transform="matrix(0.88930424,0,0,0.88930424,18.934572,17.167095)"
style="display:inline;fill:url(#linearGradient9263);fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter7107-0-8)"
d="m 107.9815,42.040847 c -0.5421,-0.403601 2.72714,-2.919358 3.41745,-2.443043 0.69031,0.476316 9.17292,7.516433 11.6566,11.636435 1.44167,2.391474 -6.81845,1.493981 -7.24444,0.356394 -0.58072,-1.550808 -6.33261,-8.435263 -7.82961,-9.549786 z"
id="path6817-1" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Leaders">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="23.282806"
y="56.571674"
id="text9269"><tspan
id="tspan9267"
x="23.282806"
y="56.571674"
style="stroke-width:0.26458332">Button 0</tspan></text>
<text
id="text9273"
y="29.795361"
x="86.34478"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="29.795361"
x="86.34478"
id="tspan9271">Button 1</tspan><tspan
style="stroke-width:0.26458332"
y="35.087029"
x="86.34478"
id="tspan9275" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="57.316246"
y="31.296835"
id="text9281"><tspan
id="tspan9279"
x="57.316246"
y="31.296835"
style="stroke-width:0.26458332">Button 2</tspan><tspan
x="57.316246"
y="36.588501"
style="stroke-width:0.26458332"
id="tspan9285" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="119.37722"
y="33.549049"
id="text9327"><tspan
id="tspan9325"
x="119.37722"
y="33.549049"
style="stroke-width:0.26458332">Button 7</tspan></text>
<text
id="text9333"
y="47.813061"
x="140.64815"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="47.813061"
x="140.64815"
id="tspan9329">Button 6</tspan><tspan
style="stroke-width:0.26458332"
y="53.104733"
x="140.64815"
id="tspan9331" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="9.5192785"
y="98.612984"
id="text9339"><tspan
id="tspan9335"
x="9.5192785"
y="98.612984"
style="stroke-width:0.26458332">Button 5</tspan><tspan
id="tspan9337"
x="9.5192785"
y="103.90463"
style="stroke-width:0.26458332" /></text>
<text
id="text9345"
y="114.12823"
x="16.025673"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="114.12823"
x="16.025673"
id="tspan9341">Button 4</tspan><tspan
style="stroke-width:0.26458332"
y="119.4199"
x="16.025673"
id="tspan9343" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="145.15257"
y="67.832733"
id="text9351"><tspan
id="tspan9347"
x="145.15257"
y="67.832733"
style="stroke-width:0.26458332">Button 3</tspan><tspan
id="tspan9349"
x="145.15257"
y="73.124397"
style="stroke-width:0.26458332" /></text>
<text
id="text9357"
y="82.847488"
x="152.15945"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="82.847488"
x="152.15945"
id="tspan9353">Button 8</tspan><tspan
style="stroke-width:0.26458332"
y="88.139153"
x="152.15945"
id="tspan9355" /></text>
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow2Mstart-3)"
d="m 108.98515,81.306499 h 41.04031"
id="path9359" />
<path
inkscape:connector-curvature="0"
id="path9765"
d="m 103.47974,76.051335 39.28859,-9.259097"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker9769-8)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker10285-2)"
d="m 126.00187,57.783384 17.5172,-7.006883"
id="path10281" />
<path
inkscape:connector-curvature="0"
id="path10809"
d="m 110.48663,48.023795 11.26105,-9.759589"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker10813-0)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker11197-1)"
d="m 91.628348,53.885635 3.25318,-19.769426"
id="path11193" />
<path
inkscape:connector-curvature="0"
id="path11799"
d="M 58.095398,70.902355 37.324968,59.140797"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker11803-0)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker12601-5)"
d="m 42.079658,87.668829 -12.26207,8.508363"
id="path12597" />
<path
inkscape:connector-curvature="0"
id="path13563"
d="m 49.587038,100.68162 -12.26207,8.50836"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker13567-6)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:0.76500005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker14005-6)"
d="M 83.620478,62.393995 69.856938,34.6167"
id="path14001" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,484 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg124"
version="1.1"
viewBox="0 0 198.4375 198.43751"
height="750"
width="750"
sodipodi:docname="logitech-g303.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview74"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="0.90533333"
inkscape:cx="375"
inkscape:cy="375"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer5" />
<defs
id="defs118">
<linearGradient
gradientUnits="userSpaceOnUse"
y2="109.32611"
x2="71.876953"
y1="123.48504"
x1="85.155098"
id="linearGradient4831"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
id="linearGradient4680-3">
<stop
id="stop4676"
offset="0"
style="stop-color:#212121;stop-opacity:1" />
<stop
id="stop4678"
offset="1"
style="stop-color:#525252;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="111.17885"
x2="78.325882"
y1="113.90072"
x1="75.392632"
gradientUnits="userSpaceOnUse"
id="linearGradient4837"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
y2="105.06921"
x2="67.821754"
y1="98.166107"
x1="58.802368"
gradientUnits="userSpaceOnUse"
id="linearGradient4820"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="94.387032"
x2="57.845005"
y1="101.39091"
x1="65.554306"
id="linearGradient4812"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
y2="75.489372"
x2="97.026817"
y1="74.89328"
x1="93.544136"
gradientUnits="userSpaceOnUse"
id="linearGradient4801"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="76.166771"
x2="102.15361"
y1="76.753265"
x1="100.40672"
id="linearGradient4796"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="145.19518"
x2="134.32263"
y1="106.60219"
x1="78.691124"
id="linearGradient4682"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.797201)"
gradientUnits="userSpaceOnUse"
y2="73.76532"
x2="52.236984"
y1="92.412109"
x1="63.324043"
id="linearGradient4705"
xlink:href="#linearGradient4680-3" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.716256)"
y2="81.23703"
x2="81.993874"
y1="81.23703"
x1="41.81852"
gradientUnits="userSpaceOnUse"
id="linearGradient4710"
xlink:href="#linearGradient4680-3" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="69.888031"
x2="82.802811"
y1="69.888031"
x1="67.125862"
id="linearGradient4763"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="65.264908"
x2="74.04789"
y1="69.896729"
x1="77.743431"
id="linearGradient4773"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="70.608902"
x2="82.567528"
y1="74.891853"
x1="80.881615"
id="linearGradient4747"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="82.01104"
x2="124.02607"
y1="82.01104"
x1="89.6782"
id="linearGradient4784"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
y2="60.248428"
x2="58.49073"
y1="69.214806"
x1="81.290771"
gradientUnits="userSpaceOnUse"
id="linearGradient4735"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="66.386375"
x2="116.9311"
y1="66.386375"
x1="58.34309"
id="linearGradient4726"
xlink:href="#linearGradient4680-3"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2281683,0,0,1.296401,-19.641241,-30.306952)"
r="41.164257"
fy="113.917"
fx="112.96842"
cy="113.917"
cx="112.96842"
id="radialGradient4695-4"
xlink:href="#linearGradient4680-3" />
<marker
style="overflow:visible"
id="Arrow2Mend-7"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5595-2" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker7210-4"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path7208-0"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker7654-6"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path7652-2" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker8458-9"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path8456-9"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
style="overflow:visible"
id="marker8938-0"
refX="0"
refY="0"
orient="auto">
<path
inkscape:connector-curvature="0"
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path8936-8" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="marker10743-1"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path10741-3"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
</defs>
<metadata
id="metadata121">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Device">
<g
id="g1971">
<path
inkscape:connector-curvature="0"
id="path4839"
d="m 33.641311,64.982766 -1.732765,5.398727 c 0,0 -0.629464,5.678443 3.26926,11.20272 5.812872,8.815493 5.94101,9.101914 13.151365,19.243577 7.210355,10.14167 20.613506,27.64865 32.12776,42.84454 3.87757,5.11741 16.967127,10.29767 21.949299,12.68881 11.002,5.28032 27.527,13.09076 40.11549,14.1146 15.07422,1.22601 22.74792,-23.13102 22.74792,-23.13102 L 141.75352,83.564426 123.90176,65.732277 102.89006,58.202973 62.293831,52.176488 45.213712,60.714006 Z"
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4726);fill-opacity:1;stroke:none;stroke-width:0.32780018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 54.76863,55.588789 -2.295328,-2.726405 -0.27808,-2.350686 c 0,0 18.167671,-1.598465 22.431514,-0.940273 4.263843,0.658192 23.729205,5.171504 34.852264,9.590788 11.12306,4.419288 9.18583,4.11904 14.42276,6.57006 -8.85487,-3.133919 -23.66007,-1.760792 -33.812723,-1.477175 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.76863,55.588789 54.76863,55.588789 Z"
id="path4728" />
<path
inkscape:connector-curvature="0"
id="path4716"
d="m 54.856148,55.855125 -2.382846,-2.992741 -0.27808,-2.350686 c 18.481975,6.870889 20.73837,7.57628 37.893815,13.7434 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.856148,55.855125 54.856148,55.855125 Z"
style="display:inline;fill:url(#linearGradient4735);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4776"
d="m 90.498682,64.587538 c 0.0014,2.415136 0.08886,3.214144 0.08886,3.214144 l 37.938998,22.41657 4.1571,0.443891 -3.58823,-15.047953 -32.119065,-9.854412 z"
style="display:inline;fill:url(#linearGradient4784);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4739"
d="m 48.926779,56.570799 c 0,0 5.569607,-2.071605 6.497874,-2.13438 4.641336,1.255515 31.870514,10.044141 37.068811,12.052968 9.897016,3.978673 20.493146,9.162891 28.404966,13.999022 5.31807,3.262227 8.52923,5.401083 8.10688,7.972533 -0.42234,2.571452 -4.45568,5.900935 -4.45568,5.900935 0,0 -13.11951,-3.389899 -13.49083,-3.641 -0.37131,-0.251104 -18.627219,-14.438453 -18.627219,-14.438453 0,0 -13.119512,-5.335949 -13.552706,-5.587054 C 78.445686,70.444268 64.831094,63.978353 64.521671,63.915577 64.212247,63.852802 48.926779,56.570799 48.926779,56.570799 Z"
style="display:inline;fill:url(#linearGradient4747);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4773);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 62.800615,61.187683 c 0.06391,-0.129654 1.75539,-2.692898 4.595099,-4.082141 1.130065,-0.55285 4.463428,-1.655606 6.038322,-1.200179 4.493777,1.299505 7.905733,3.09382 12.483497,10.149265 -3.2066,1.658274 -3.2066,1.658274 -3.2066,1.658274 l -2.49426,0.310726 z"
id="path4765" />
<path
inkscape:connector-curvature="0"
id="path4755"
d="m 62.800615,61.187683 c 0.08752,-0.177557 3.063124,-5.903769 8.708027,-3.639918 5.644906,2.263853 10.545906,10.120748 10.545906,10.120748 l -1.837875,0.355115 z"
style="display:inline;fill:url(#linearGradient4763);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4710);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 81.061034,68.55619 c 0,0 -6.675185,12.538586 -10.603076,22.010152 -1.049126,2.529831 -2.28668,5.867231 -2.803926,7.547057 -0.660926,2.146451 -0.08433,2.769521 -0.397665,4.358811 -3.844082,-2.632003 -32.505527,-27.735224 -34.22755,-29.787815 -0.242782,-0.289387 -1.233891,-1.962381 -1.42236,-4.307299 -0.05219,-0.649308 -0.04284,-1.350134 0.06099,-2.087368 0.836918,-5.94284 11.1851,-12.607804 11.1851,-12.607804 z"
id="path4707" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#radialGradient4695-4);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 82.41522,69.014086 c 0,0 23.31399,10.073283 38.80002,21.370661 1.81334,1.322871 4.49209,1.676486 6.63621,-0.04062 2.14412,-1.717108 1.62492,-3.937097 -0.92121,-6.104499 -4.95885,-4.221241 -6.85739,-5.122344 -13.18638,-8.905281 -7.90195,-4.723139 -16.853771,-8.967037 -23.245174,-10.746814 9.140702,-0.572366 30.023744,-1.337857 33.403074,1.144738 8.87412,3.960851 24.30645,16.663516 31.24281,27.830947 8.63308,13.899132 12.33164,22.248122 14.23506,36.388812 2.80518,20.83995 -16.13732,43.5 -26.85791,40.5237 3.57946,-0.6342 7.33514,-2.175 6.9966,-5.15132 -0.74082,-6.51284 -8.57647,-16.59867 -48.52475,-38.11975 -18.315639,-9.86707 -32.387452,-23.46711 -32.387452,-23.46711 0,0 -0.214496,-1.83679 0.169271,-3.37698 C 71.534502,89.287367 82.41522,69.014083 82.41522,69.014083 Z"
id="path4670" />
<path
inkscape:connector-curvature="0"
id="path178"
d="m 67.336162,99.153458 -0.07979,3.237812 C 63.412286,99.759262 35.095451,75.716531 33.028818,72.77516 c -1.88514,-2.683054 -1.67797,-6.628929 -0.815272,-8.362198 -0.06626,1.61221 -0.485638,3.84076 1.152105,5.623249 7.675602,8.353979 25.95005,21.003692 33.970511,29.117247 z"
style="display:inline;fill:url(#linearGradient4705);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4672"
d="m 142.52172,170.47574 c 3.57946,-0.6342 7.33514,-2.17499 6.9966,-5.15132 -0.74082,-6.51285 -8.57647,-16.59867 -48.52476,-38.11975 -18.315635,-9.86707 -32.387446,-23.46711 -32.387446,-23.46711 0,0 -0.214498,-1.8368 0.169271,-3.37698 3.725669,4.47916 22.509918,18.21415 41.851065,29.0174 55.62333,31.06912 43.85529,42.27142 31.89527,41.09776 z"
style="display:inline;fill:url(#linearGradient4682);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4788"
d="m 91.506481,71.019901 c 0.743609,0.908331 11.844809,6.076214 14.221649,7.257645 0.71803,0.356899 1.1815,0.799004 2.31924,0.621448 1.13772,-0.177558 2.35863,-1.316437 2.47237,-1.642404 0.12819,-0.367406 -2.52196,-5.346011 -2.73493,-5.570848 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -1.679248,0.660653 -2.406747,1.242898 -0.758403,0.606982 -2.320732,1.856577 -1.969149,2.286046 z"
style="display:inline;fill:url(#linearGradient4796);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4801);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 105.24679,73.239364 c 0.34525,0.02969 2.75099,-1.328785 2.53802,-1.553622 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -2.23807,0.99583 -2.472384,1.487039 -0.208466,0.437022 10.535617,4.077407 11.836797,4.261368 z"
id="path4798" />
<path
inkscape:connector-curvature="0"
id="path4804"
d="m 48.060396,93.734116 16.089967,15.317314 1.980305,-0.87885 1.732766,-3.76656 -17.080119,-14.81511 -1.856536,1.129967 z"
style="display:inline;fill:url(#linearGradient4812);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4820);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 48.060396,93.734116 16.089967,15.317314 1.608998,-3.8921 C 61.694393,101.39187 50.213564,91.368976 48.926779,90.720877 Z"
id="path4814" />
<path
inkscape:connector-curvature="0"
style="display:inline;fill:url(#linearGradient4837);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 7.5516,-4.23009 10.658617,-6.2986 0.393265,-0.26182 1.06751,-0.26234 -0.417721,-1.26676 -1.485226,-1.0044 -15.684249,-10.57631 -21.967626,-16.10646 -0.272557,-0.23987 -2.024894,0.70814 -2.197279,1.00972 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
id="path4833" />
<path
inkscape:connector-curvature="0"
id="path4823"
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 5.494927,-2.76524 8.601948,-4.83374 0.393264,-0.26183 1.067506,-0.70624 -0.417724,-1.71067 -1.485226,-1.0044 -14.896587,-10.13241 -21.179966,-15.66256 -0.272558,-0.23988 -0.755882,-0.75671 -0.928267,-0.45513 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
style="display:inline;fill:url(#linearGradient4831);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path4668"
d="m 87.372005,82.225427 c 0,0 19.527815,7.279613 31.390235,17.304521 0,0 3.8591,1.194482 5.60489,-0.183766 1.74578,-1.378252 1.19448,-3.032155 -0.64318,-4.686055 -1.83767,-1.6539 -20.39812,-13.414976 -29.770224,-15.987711 7.442554,-0.459415 24.445964,-1.073843 27.197484,0.918834 7.22549,3.179214 19.79081,13.375124 25.43853,22.33877 7.02923,11.15626 10.04068,17.85767 11.59048,29.20782 2.28404,16.72738 -13.13933,34.91569 -21.86825,32.52672 2.91447,-0.50904 5.97242,-1.74578 5.69677,-4.13475 -0.60319,-5.2276 -6.98314,-13.32309 -39.50986,-30.59717 -14.912971,-7.91989 -26.370531,-18.8361 -26.370531,-18.8361 0,0 -0.174647,-1.47432 0.137824,-2.71056 C 78.5127,98.497965 87.372005,82.225427 87.372005,82.225427 Z"
style="fill:none;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Leaders">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="14.064545"
y="42.284489"
id="text4889"><tspan
id="tspan4887"
x="14.064545"
y="42.284489"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">Button 0</tspan></text>
<text
id="text4977"
y="41.314796"
x="99.894806"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332"
y="41.314796"
x="99.894806"
id="tspan4979">Button 2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="55.51276"
y="30.319952"
id="text4985"><tspan
x="55.51276"
y="30.319952"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332"
id="tspan4987">Button 1</tspan></text>
<text
id="text4993"
y="122.63442"
x="20.689524"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332"
y="122.63442"
x="20.689524"
id="tspan4995">Button 4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="55.262302"
y="153.98589"
id="text5001"><tspan
x="55.262302"
y="153.98589"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332"
id="tspan5003">Button 3</tspan></text>
<text
id="text5009"
y="63.376724"
x="141.62805"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332"
y="63.376724"
x="141.62805"
id="tspan5011">Button 5</tspan></text>
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend-7)"
d="M 65.843201,148.27126 72.399015,138.295"
id="path5023" />
<path
inkscape:connector-curvature="0"
id="path7206"
d="m 41.615182,120.90785 13.396667,-6.27079"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7210-4)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7654-6)"
d="m 22.80284,45.373441 11.401419,9.121126"
id="path7650" />
<path
inkscape:connector-curvature="0"
id="path8454"
d="m 66.128236,34.542092 4.275532,11.686447"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8458-9)" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8938-0)"
d="M 98.052208,43.663228 82.660292,57.629959"
id="path8934" />
<path
inkscape:connector-curvature="0"
id="path10739"
d="M 140.23745,65.04089 111.7339,70.171521"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10743-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1,564 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
viewBox="0 0 750.00004 749.99998"
height="750"
width="750"
sodipodi:docname="logitech-g502.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview105"
showgrid="false"
inkscape:zoom="0.90533333"
inkscape:cx="346.71574"
inkscape:cy="388.7347"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs4">
<linearGradient
id="linearGradient4449">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4451" />
<stop
id="stop4059"
offset="0.24691147"
style="stop-color:#3b3b3b;stop-opacity:1;" />
<stop
id="stop4057"
offset="0.84132797"
style="stop-color:#777777;stop-opacity:1;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
id="linearGradient4372">
<stop
style="stop-color:#3d444c;stop-opacity:1"
offset="0"
id="stop4374" />
<stop
style="stop-color:#8f9aaa;stop-opacity:1"
offset="1"
id="stop4376" />
</linearGradient>
<linearGradient
id="linearGradient4327">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4329" />
<stop
style="stop-color:#969696;stop-opacity:1"
offset="1"
id="stop4331" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4372"
id="linearGradient4378-3"
x1="476.00003"
y1="513.00006"
x2="559.50006"
y2="463.50003"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4327"
id="linearGradient4333-7"
x1="-258.85849"
y1="636.73883"
x2="-210.58292"
y2="669.61383"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient4449"
id="linearGradient4562-2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.672119,1.672119,0,512.07567,646.09377)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
xlink:href="#linearGradient4449"
id="linearGradient4623-2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.6721192,-1.6721192,0,585.53788,701.25516)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Device">
<g
id="layer1-2"
transform="matrix(1.066667,0,0,1.066667,543.92842,-223.56879)"
style="display:inline">
<g
transform="matrix(0.92282933,0,0,0.92282933,9.1598029,28.961215)"
id="g4390"
style="display:inline;stroke-width:1.08362401">
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -226.16095,683.58782 c -6.01535,-13.02364 -13,-16.5 -13,-16.5 l -11.25,-3.375 -116.45795,-88.57547 11.4905,-82.02437 7.62132,1.97703 6.89061,-13.15685 c -18.38478,2.65165 -27.23986,-1.01777 -28.47729,-2.60876 -1.23744,-1.59099 0.17677,-3.18198 0.17677,-3.18198 0,0 7.43505,-10.39747 47.55294,-23.33452 117.72759,-37.96429 194.75285,-32.63933 310.328127,14.65494 101.699787,41.61632 127.995243,117.50993 130.641353,159.47011 0,0 -2.38649,0.17677 -5.74524,5.03813 -3.35876,4.86136 6.0104,17.05896 3.53553,28.72622 -2.47487,11.66726 -28.637827,53.29817 -45.166448,48.70198 -16.528622,-4.5962 -39.067651,-6.98268 -55.154331,-3.00521 -16.08667977,3.97748 -95.017477,43.75224 -100.144001,46.66905 -5.126525,2.91682 -19.26866,10.42983 -25.36746,10.87177 -6.09879,0.44194 -18.29639,-4.06586 -45.25483,-14.05375 -26.95845,-9.98788 -54.09367,-22.98097 -61.25313,-32.88046 -7.15946,-9.8995 -4.95112,-20.38922 -10.96647,-33.41286 z"
id="path4435"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4378-3);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 564.2793,394.82812 c -3.92575,-0.10626 -7.28936,3.75042 -13.08985,11.8711 -8.83883,12.37437 -39.24401,61.16451 -77.07422,75.30664 -37.83021,14.14214 -97.93406,2.12147 -130.10742,-1.41406 -32.07532,-3.52476 -80.61133,-16.61719 -80.61133,-16.61719 l -30.16601,4.00391 39.14453,29.77148 11.25,3.375 c 0,0 6.98465,3.47636 13,16.5 6.01535,13.02364 3.80734,23.51261 10.9668,33.41211 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 6.0988,-0.44194 20.24066,-7.95623 25.36719,-10.87305 5.12652,-2.91681 84.05785,-42.69049 100.14453,-46.66797 16.08668,-3.97747 38.62567,-1.59229 55.15429,3.00391 16.52863,4.59619 42.69115,-37.03392 45.16602,-48.70117 0.81145,-3.82542 0.34164,-7.70307 -0.52734,-11.36524 -4.70923,-11.20032 -11.76875,-25.18057 -21.7461,-38.13281 -23.82425,-30.92783 -38.18467,-40.65753 -46.3164,-47.02149 -2.79529,-2.18761 -5.00616,-3.33105 -7.0625,-3.38672 z"
transform="translate(-522.78594,165.96281)"
id="path4362"
inkscape:connector-curvature="0" />
<g
id="g4356"
style="stroke-width:1.08362401">
<path
id="path4417"
transform="translate(-522.78594,165.96281)"
d="m 130.91406,379.34375 c -0.46995,0.14042 -0.93877,0.27563 -1.41015,0.42187 0,10e-6 -1.6703,5.53928 -1.51758,6.25196 l 51.97265,21.91992 23.86524,-17.50195 2.72461,-3.55664 c -0.22885,-0.14243 -0.45999,-0.27609 -0.68945,-0.41602 -27.39877,-3.31358 -52.27682,-5.25289 -75.04493,-6.2793 l 0.0996,-0.83984 z"
style="fill:#2e2d2b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4422"
transform="translate(-522.78594,165.96281)"
d="m 128.01367,386.0293 4.48633,9.0957 66,39.375 -18.53906,-26.56445 -0.002,0.002 -51.94531,-21.9082 z"
style="fill:#13130f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4427"
transform="translate(-522.78594,165.96281)"
d="m 203.82422,390.61328 c 0,0 -0.57509,0.25215 -0.60156,0.26367 l -23.26172,17.0586 18.38281,26.33984 -1.14844,-4.50586 0.79492,-17.32422 z"
style="fill:#7c7a79;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:#3d4144;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 411.19922,269.32812 C 389.02158,276.55183 382.23256,283.7763 371.75,291 l 25.375,6.25 c 18.2282,-19.41084 23.88453,-20.47312 31.20117,-23.95898 -5.76229,-1.45746 -11.46778,-2.78139 -17.12695,-3.9629 z"
transform="translate(-522.78594,165.96281)"
id="path4216"
inkscape:connector-curvature="0" />
<path
style="fill:#3c4247;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -170.91095,464.08782 -8.5,16.125 35.75,3.25 1.625,-16.25 z"
id="path4220"
inkscape:connector-curvature="0" />
<path
style="fill:#363c41;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 411.17969,269.33398 c -24.50302,-5.11518 -48.18402,-7.65405 -72.22657,-7.57031 -42.56105,0.14824 -86.27544,8.47266 -137.78124,25.08203 -40.11789,12.93705 -47.55274,23.33399 -47.55274,23.33399 0,0 -0.48629,0.56241 -0.63476,1.3457 l 0.10351,0.0684 c 65.05383,-30.40559 116.42376,-36.77027 218.33008,-20.63869 11.09267,-7.17661 17.60011,-14.39959 39.76172,-21.62112 z"
transform="translate(-522.78594,165.96281)"
id="path4226"
inkscape:connector-curvature="0" />
<path
style="fill:#10f5fa;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 296.87305,518.20312 c 5.68645,12.75421 3.66653,23.08278 10.71875,32.83399 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 5.82656,-0.42222 18.90685,-7.25764 24.54101,-10.41407 -0.55038,-0.0177 -1.10725,-0.03 -1.64062,-0.0586 -7,-0.375 -17.75,-3.625 -26.375,-6.5 -8.625,-2.875 -67.14947,-20.67049 -76.375,-33.125 -7.10507,-9.59187 -5.33684,-16.54135 -8.83008,-19.27148 -2.49111,-1.94692 -8.34261,-3.73063 -12.5039,-5.15625 -3.08671,-1.05747 -11.18273,-3.67568 -16.04297,-5.24415 z"
transform="translate(-522.78594,165.96281)"
id="path4263"
inkscape:connector-curvature="0" />
<g
id="g4348"
style="stroke-width:1.08362401">
<path
id="path4228"
transform="translate(-522.78594,165.96281)"
d="m 244.0293,281.64062 c -11.87933,0.21005 -21.28719,4.70945 -25.45899,14.41407 l -7.76367,15.2207 c 4.63005,-8.00151 13.38623,-11.7657 24.20703,-11.95703 13.84985,-0.24489 31.05521,5.35529 47.24414,15.31641 4.24517,-2.44738 6.87171,-7.03619 7.65625,-8.34375 0.83684,-1.39473 3.09281,-4.54246 4.70703,-7.20118 -17.13681,-11.29215 -35.78244,-17.71107 -50.59179,-17.44922 z m -33.22266,29.63477 c -0.45292,0.78273 -0.88022,1.59229 -1.25195,2.45703 z"
style="fill:#a6a09b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
transform="translate(-522.78594,165.96281)"
id="path4247"
d="m 210.77539,311.25976 -1.12305,2.28126 c -0.45554,2.37144 2.75076,4.2831 5.21875,3.9746 2.82843,-0.35354 20.06602,-2.56346 32.97071,-2.74023 12.9047,-0.17678 22.09591,1.76761 29.34375,1.41406 1.88682,-0.092 3.57816,-0.69332 5.07226,-1.55468 -16.18893,-9.96112 -33.39429,-15.5613 -47.24414,-15.31641 -10.8208,0.19133 -19.60823,3.93989 -24.23828,11.9414 z"
style="fill:#0c0d08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:#111419;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -179.35432,480.17165 -2.95971,5.51668 39.24443,5.56847 -0.88388,-7.86656 z"
id="path4258"
inkscape:connector-curvature="0" />
<path
style="fill:#282d32;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -143.07496,491.2041 -1.00352,-7.90761 2.03293,-16.10721 1.45082,6.56663 z"
id="path4260"
inkscape:connector-curvature="0" />
<g
id="g4352"
style="stroke-width:1.08362401">
<path
id="path4262"
d="m -313.91094,553.83781 -2.375,3.5 -3.875,14.125 93.375,-1.625 c -21.95804,-4.72268 -46.10785,-9.6343 -87.125,-16 z"
style="fill:#2f333a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4264"
d="m -320.16094,571.44718 -3.125,23.01563 3.25,7.125 99.5,-15.375 -6.29687,-16.40625 z"
style="fill:#585958;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g4335"
style="stroke-width:1.08362401">
<path
id="path4288"
d="m -295.16094,608.46281 6.625,27.125 27.125,5.875 c 0,0 38.75,14.5 45.75,29.125 l 5.5,0.875 2.375,-4.625 c 0,0 -13.875,-23.75 -49.625,-33.375 l -1,-1.25 2.25,-11.25 z"
style="fill:url(#linearGradient4333-7);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4333-7);stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4290"
transform="translate(-522.78594,165.96281)"
d="M 235.18359,469.82617 272.125,497.75 l 35,6.875 C 300.125,490 261.375,475.5 261.375,475.5 Z"
style="fill:#1f2021;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g4297"
style="stroke-width:1.08362401">
<path
id="path4266"
d="m -271.28594,618.46281 4,7 85.38128,13.44194 9.61872,-8.44194 z"
style="fill:#5e5d5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4268"
d="m -181.07659,638.77695 c 0,0 22.18548,12.55115 -5.48008,8.04334 -27.66555,-4.5078 -67.97064,-12.55114 -67.97064,-12.55114 l -12.72792,-8.75045 z"
style="fill:#242422;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4270"
d="m -172.41453,630.38006 -9.45755,8.3085 9.28077,8.3969 9.54594,-5.3033 z"
style="fill:#5e6570;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4280"
d="m -271.48416,618.56636 2.19822,-8.60355 103.25,9.875 6,18.125 -2.625,3.875 -9.60983,-10.91789 z"
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g4305"
style="stroke-width:1.08362401">
<path
id="path4272"
d="m -164.98991,632.50138 6.18718,9.72272 75.041708,8.22011 8.131734,-6.54073 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
style="fill:#676763;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4274"
d="m -70.32599,631.08717 5.48008,5.39169 -5.74524,12.90469 -5.204655,-5.54257 c 0.08832,-4.98178 3.353501,-8.62593 5.469815,-12.75381 z"
style="fill:#2f343b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4276"
d="m -83.58424,650.17905 3.8007,4.06586 -77.87014,-6.89429 -1.15104,-5.14215 z"
style="fill:#202328;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:#97a6b5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -70.59115,649.38355 -9.1397,4.91406 -3.894905,-4.1034 7.819685,-6.37912 z"
id="path4278"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:#676769;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -153.03036,495.18342 44.96255,6.76837 1.76776,125.51145 -32.51219,-3.18198 z"
id="path4292"
inkscape:connector-curvature="0" />
<path
id="path4303"
d="m -164.98991,632.50138 89.360622,11.4021 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<g
id="g4282"
style="stroke-width:1.08362401">
<path
id="path4244"
d="m -283.96063,605.18939 1.59099,4.06586 144.42656,16.26346 -6.01041,-45.07806 z"
style="fill:#9b9994;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4246"
transform="translate(-522.78594,165.96281)"
d="m 312.64258,435.04297 -5.01172,0.64453 8.00195,8.8418 5.88281,0.41015 z"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4248"
transform="translate(-522.78594,165.96281)"
d="m 331.68945,432.58984 -4.78515,0.61524 11.86718,12.93945 6.72461,0.4707 z"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4250"
transform="translate(-522.78594,165.96281)"
d="m 351.97266,429.97852 -6.13282,0.78906 16.58594,17.0293 7.58399,0.52929 z"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g4339"
style="stroke-width:1.08362401">
<path
id="path3608"
d="m -386.31433,498.06271 -5.65686,48.08326 c 45.99186,2.07336 100.55399,7.85718 167.23075,21.21321 l 1.06066,3.0052 c 23.24045,-1.15617 46.44002,-2.32824 77.95852,-0.26516 l 3.35876,3.62392 -10.6066,-78.48885 c -119.63944,-15.8417 -179.55343,-5.16228 -233.34523,2.82842 z"
style="fill:#4c5053;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4412"
transform="translate(-522.78594,165.96281)"
d="m 344.67578,403.00977 c -16.50546,-0.0586 -30.99426,0.6673 -45.49414,1.38867 l 6.64258,15.02929 74.77539,-10.96093 -0.94727,-1.53907 -2.58789,-2.79101 c -11.81943,-0.77366 -22.46808,-1.09174 -32.38867,-1.12695 z"
style="fill:#413d44;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path4242"
d="m -296.22345,497.71282 4.375,6.6875 6.875,-6.8125 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<g
id="g4344"
style="stroke:none;stroke-width:1.08362401">
<path
id="path4234"
transform="translate(-522.78594,165.96281)"
d="m 428.32422,273.29297 c -7.29616,3.47575 -12.94858,4.55152 -31.06055,23.8125 0.0479,0.0864 0.0803,0.17102 0.13086,0.25781 6.62912,19.7106 10.60547,165.375 10.60547,165.375 0,0 41.19295,7.2655 67.125,1.38672 22.33947,-5.06434 38.625,-29.625 51.125,-42.625 12.5,-13 24.89365,-35.29164 33.5,-37.875 6.89763,-2.07046 15.8234,4.4109 29.125,12.375 33.4418,20.02269 42.89394,39.55603 52.79297,65.09375 0.30214,-0.10531 0.47265,-0.12305 0.47265,-0.12305 C 639.49453,419.01054 613.19977,343.11632 511.5,301.5 481.65769,289.2883 454.39027,279.88532 428.32422,273.29297 Z"
style="fill:#6d747e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
<ellipse
ry="29.875"
rx="32.25"
cy="561.08783"
cx="-58.535938"
id="path4261"
style="opacity:1;fill:#2cbfff;fill-opacity:1;stroke:none;stroke-width:1.62543607;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<path
style="fill:#202124;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -205.53595,454.96282 -11.375,19 21.5,-0.875 10.875,-18.875 z"
id="path4218"
inkscape:connector-curvature="0" />
<path
style="fill:#121518;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -222.88428,483.39024 6.01577,-9.47808 21.47301,-0.86336 1.23744,11.49049 z"
id="path4254"
inkscape:connector-curvature="0" />
<path
style="fill:#1a1e22;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08362401px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -195.50442,473.05324 10.88157,-18.79455 2.39721,10.39322 -12.00029,19.91863 z"
id="path4256"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Leaders">
<path
style="display:inline;fill:url(#linearGradient4562-2);fill-opacity:1;stroke:none;stroke-width:1.06666696"
d="m 537.54283,592.59247 5.47684,3.16138 5.47357,3.16133 v -3.60551 h 11.57746 l -1.5676,-2.7172 1.5676,-2.7172 h -11.57746 v -3.60549 l -5.47357,3.16135 z"
id="path4556"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4623-2);fill-opacity:1;stroke:none;stroke-width:1.06666696"
d="m 560.07072,647.75385 -5.47685,3.16137 -5.47357,3.16132 v -3.60549 h -11.57747 l 1.56762,-2.7172 -1.56762,-2.71719 h 11.57747 v -3.60551 l 5.47357,3.16136 z"
id="use4558"
inkscape:connector-curvature="0" />
<text
id="text4489"
y="326.48422"
x="70.888794"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="326.48422"
x="70.888794"
id="tspan4491">Button0</tspan></text>
<text
id="text4505"
y="598.14478"
x="570.61731"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="598.14478"
x="570.61731"
id="tspan4507">Button10</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="570.65088"
y="653.30615"
id="text4509"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
id="tspan4511"
x="570.65088"
y="653.30615">Button9</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="68.277954"
y="388.80585"
id="text4440"><tspan
id="tspan4442"
x="68.277954"
y="388.80585"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button7</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 136.79589,322.56395 h 77.95666"
id="path4448"
inkscape:connector-curvature="0" />
<path
id="path4450"
d="M 344.21631,234.86269 381.80255,118.62372"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="180.61809"
y="131.11789"
id="text4452"><tspan
id="tspan4454"
x="180.61809"
y="131.11789"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button2</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 280.18048,255.0479 214.05652,136.72082"
id="path4456"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 332.38361,561.30626 424.95716,449.24354"
id="path4466"
inkscape:connector-curvature="0" />
<text
id="text4468"
y="438.99133"
x="76.613747"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="438.99133"
x="76.613747"
id="tspan4470">Button6</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="124.46452"
y="486.74979"
id="text4472"><tspan
id="tspan4474"
x="124.46452"
y="486.74979"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button4</tspan></text>
<text
id="text4476"
y="535.11047"
x="152.34004"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="535.11047"
x="152.34004"
id="tspan4478">Button5</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="299.23001"
y="578.30023"
id="text4480"><tspan
id="tspan4482"
x="299.23001"
y="578.30023"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button3</tspan></text>
<text
id="text4484"
y="117.37291"
x="382.20294"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="117.37291"
x="382.20294"
id="tspan4486">Button1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="528.19232"
y="164.23615"
id="text4488"><tspan
id="tspan4490"
x="528.19232"
y="164.23615"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button8</tspan></text>
<path
id="path4492"
d="M 136.09985,377.55125 195.26339,365.0225"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 141.66819,424.88208 266.25965,381.72751"
id="path4494"
inkscape:connector-curvature="0" />
<path
id="path4496"
d="m 191.78319,474.30105 138.5123,-43.15458"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 198.04756,519.54376 98.83792,-60.55562"
id="path4498"
inkscape:connector-curvature="0" />
<path
id="path4500"
d="M 401.98779,271.75291 523.79509,166.65062"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,594 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg8"
version="1.1"
viewBox="0 0 198.4375 198.43751"
height="750"
width="750"
sodipodi:docname="logitech-g9.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview94"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="0.62933333"
inkscape:cx="285.67971"
inkscape:cy="405.53127"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer3"
inkscape:document-rotation="0" />
<defs
id="defs2">
<linearGradient
id="linearGradient4505">
<stop
id="stop4501"
offset="0"
style="stop-color:#989899;stop-opacity:1" />
<stop
id="stop4503"
offset="1"
style="stop-color:#423f43;stop-opacity:0" />
</linearGradient>
<linearGradient
id="linearGradient4330">
<stop
id="stop4326"
offset="0"
style="stop-color:#636166;stop-opacity:1" />
<stop
id="stop4328"
offset="1"
style="stop-color:#413f43;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4308">
<stop
id="stop4304"
offset="0"
style="stop-color:#444248;stop-opacity:1" />
<stop
style="stop-color:#48474b;stop-opacity:1"
offset="0.33914274"
id="stop4312" />
<stop
id="stop4306"
offset="1"
style="stop-color:#b2b2b4;stop-opacity:0" />
</linearGradient>
<linearGradient
id="linearGradient4379">
<stop
id="stop4375"
offset="0"
style="stop-color:#45494d;stop-opacity:1" />
<stop
id="stop4377"
offset="1"
style="stop-color:#25262a;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4351">
<stop
id="stop4347"
offset="0"
style="stop-color:#9b9b9f;stop-opacity:1" />
<stop
style="stop-color:#ffffff;stop-opacity:1"
offset="0.49072835"
id="stop4355" />
<stop
id="stop4349"
offset="1"
style="stop-color:#8e8d90;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4341">
<stop
id="stop4337"
offset="0"
style="stop-color:#120b11;stop-opacity:1" />
<stop
id="stop4339"
offset="1"
style="stop-color:#27282d;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4327">
<stop
id="stop4323"
offset="0"
style="stop-color:#100f15;stop-opacity:1" />
<stop
id="stop4325"
offset="1"
style="stop-color:#595d62;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1742912,-9.3841221,-5.8762942)"
y2="22.688826"
x2="105.51226"
y1="188.74203"
x1="103.14564"
gradientUnits="userSpaceOnUse"
id="linearGradient4331"
xlink:href="#linearGradient4327" />
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1742912,-9.3841221,-5.8762942)"
gradientUnits="userSpaceOnUse"
y2="111.9789"
x2="101.38398"
y1="47.607136"
x1="101.79689"
id="linearGradient4343"
xlink:href="#linearGradient4341" />
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1683052,-9.536801,-5.7076406)"
gradientUnits="userSpaceOnUse"
y2="78.818336"
x2="106.56455"
y1="58.741718"
x1="106.52042"
id="linearGradient4353"
xlink:href="#linearGradient4351" />
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1742912,-9.3841221,-5.8762942)"
gradientUnits="userSpaceOnUse"
y2="104.87594"
x2="54.881187"
y1="106.28905"
x1="65.710442"
id="linearGradient4381"
xlink:href="#linearGradient4379" />
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1742912,-9.3841221,-5.8762942)"
gradientUnits="userSpaceOnUse"
y2="32.342125"
x2="105.20406"
y1="50.405422"
x1="105.60937"
id="linearGradient4310"
xlink:href="#linearGradient4308" />
<linearGradient
gradientTransform="matrix(1.1742912,0,0,1.1742912,-310.58744,-20.716767)"
gradientUnits="userSpaceOnUse"
y2="92.680016"
x2="396.11249"
y1="83.560425"
x1="368.85941"
id="linearGradient4332"
xlink:href="#linearGradient4330" />
<linearGradient
gradientTransform="matrix(1.1730673,-0.05360072,0.05360072,1.1730673,-272.43538,-5.5525684)"
gradientUnits="userSpaceOnUse"
y2="82.570068"
x2="312.97284"
y1="83.391426"
x1="324.6431"
id="linearGradient4507"
xlink:href="#linearGradient4505" />
<linearGradient
y2="101.28305"
x2="306.84976"
y1="104.65936"
x1="307.03534"
gradientTransform="matrix(1.1730673,-0.05360072,0.05360072,1.1730673,-272.43538,-5.5525684)"
gradientUnits="userSpaceOnUse"
id="linearGradient4511"
xlink:href="#linearGradient4505" />
<linearGradient
xlink:href="#linearGradient4449"
id="linearGradient4562-2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.44241483,0,0,0.44241483,141.87301,147.82897)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
id="linearGradient4449">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4451" />
<stop
id="stop4059"
offset="0.24691147"
style="stop-color:#3b3b3b;stop-opacity:1;" />
<stop
id="stop4057"
offset="0.84132797"
style="stop-color:#777777;stop-opacity:1;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient4449"
id="linearGradient4623-2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.44241488,0,0,-0.44241488,141.87299,181.86062)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Device"
style="display:inline">
<g
transform="translate(-1.0583334,1.5875001)"
style="display:inline;opacity:1"
id="layer2-0">
<g
transform="translate(-3.4704866,-7.0405558)"
id="g4594">
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#3a373a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 77.177399,97.902294 6.104879,-45.161826 c 0,0 23.584792,-4.178672 24.946992,-4.230997 1.36216,-0.05233 2.90708,0.284061 2.90708,0.284061 l -1.7858,46.32423 c -12.77599,0.205474 -29.351306,3.51043 -32.173151,2.784532 z"
id="path4497" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#2c282c;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 77.484288,103.8942 0.485337,-6.617983 c 8.461322,-0.795948 19.932848,-1.405469 31.644865,-2.832276 l -0.13147,6.093759 c -2.00828,2.01378 -25.087068,3.75167 -31.998732,3.35649 z"
id="path4492" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4310);fill-opacity:1;fill-rule:evenodd;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 112.45854,48.673649 -0.15185,-14.682308 4.10547,-0.275969 0.10898,15.201736 z"
id="path4294" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4381);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 77.876085,56.839675 c 0,0 -1.471527,0.83341 -1.810925,1.7849 -0.339393,0.951491 -16.168851,35.787062 -19.676329,50.819095 -3.507477,15.03202 -2.371756,19.94152 -2.371756,19.94152 0,0 3.861947,10.45097 8.329276,18.52531 4.467326,8.07435 4.961694,8.89575 4.961694,8.89575 l -0.213903,-19.5262 1.703903,-0.46404 2.744193,-39.166022 z"
id="path4365" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4331);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 78.27115,54.434668 -7.48213,43.568266 c 0,0 0.476579,1.029381 0.324073,1.990126 -0.152506,0.96074 -2.420477,36.18422 -2.420477,36.18422 -0.355121,0.15828 -1.325027,0.33622 -2.042764,-0.16606 l 0.383815,20.3658 c 0,0 16.260517,24.29325 21.731528,26.4292 5.471007,2.13595 33.712475,5.76449 45.045255,-5.04393 11.33279,-10.80844 18.13817,-40.40294 19.0246,-42.62467 0.88643,-2.22174 0.97221,-22.60336 0.63861,-27.0554 -0.33359,-4.45204 -5.24224,-53.518879 -5.24224,-53.518879 l -0.75298,-0.574736 -0.34314,-1.818558 -3.28832,-0.446063 -1.05801,1.612684 c 0,0 0.65473,55.280832 0.0828,57.236642 -3.50339,8.99181 -62.826338,16.12105 -65.71582,10.5305 0,0 -0.343145,-19.51523 0.171552,-27.69875 0.514695,-8.183518 6.46227,-40.694595 6.46227,-40.694595 l -1.477365,-0.386014 z"
id="path4299" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#0a0309;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 143.68572,52.718279 -1.08758,-0.105064 -0.7152,58.124735 c -25.40904,10.09051 -46.263283,10.35133 -64.709748,5.41595 -0.569129,-6.64228 2.723755,-40.412798 6.551495,-63.38927 -1.329573,2.096014 -11.038066,45.857103 -6.432098,72.44326 31.026281,-1.3617 55.581991,-4.72092 67.571961,-13.01971 z"
id="path4363" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#100f15;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 147.48209,53.990659 c 0,0 3.60862,62.216321 3.18362,73.553921 -0.42504,11.3376 -3.08536,24.73061 -3.08536,24.73061 0.17938,-0.42088 3.57331,-10.50586 5.40745,-17.70147 0.71802,-5.20464 0.79094,-21.82933 0.50887,-26.13904 -0.35573,-5.43493 -4.00333,-41.108137 -5.26548,-53.873474 z"
id="path4333" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4343);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 83.824604,52.738709 -1.250972,-0.245922 c 0,0 -8.059607,43.356337 -8.166174,56.967173 -0.106625,13.61084 -5.055488,24.88381 34.888512,19.75206 39.94401,-5.13176 36.61892,-20.58117 36.61892,-20.58117 l -1.76914,-56.190652 -0.85293,0.06392 c 0,0 1.96242,55.618052 1.12783,57.633402 -0.90305,5.11422 -29.75059,11.23217 -37.2287,12.06204 C 98.789172,123.0647 77.702414,124.85494 76.780689,120.5 75.468184,93.62462 83.824604,52.738707 83.824604,52.738707 Z"
id="path4335" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#0a0309;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 110.34556,64.349805 -0.11449,21.523245 10.83825,-0.04674 0.4938,-21.169092 z"
id="path4361" />
<rect
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4353);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083334;stroke-linecap:round;paint-order:markers stroke fill"
id="rect4345"
width="8.5005722"
height="19.579855"
x="111.05955"
y="65.467842"
ry="2.078804" />
<rect
style="color:#000000;overflow:visible;vector-effect:none;fill:#313237;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
id="rect4357"
width="4.8539634"
height="19.804958"
x="112.85114"
y="65.303093"
ry="0.51506227" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#525054;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.74083328;stroke-linecap:round;paint-order:markers stroke fill"
d="m 110.93569,49.34497 c 0.17831,-0.317361 0.29848,-0.818988 0.53493,-0.952083 l 11.85679,0.387209 c 3.57996,0.438472 11.48189,1.107237 18.90241,3.168225 l 0.58904,0.628053 c 0.4516,18.61888 0.74216,35.257569 0.26336,57.894286 0,0 -0.62934,5.72246 -26.94491,9.97842 -26.315559,4.25595 -37.605807,1.37998 -37.605807,1.37998 -0.623452,-0.24916 -1.115754,-0.79276 -1.30372,-1.94276 -0.149634,-0.91548 -0.142638,-6.91509 -0.142638,-6.91509 10.089039,-2.41284 25.379115,-1.9056 28.541445,-3.69477 4.79494,-1.81161 4.35855,-13.193339 4.35855,-13.193339 l 0.22511,-10.433667 c 2.01048,-0.120202 9.88363,1.14486 9.98353,-2.014334 l -0.12176,-17.186068 c -0.13242,-2.593108 -6.39547,-1.529455 -9.45682,-1.614711 z"
id="path4359" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#020007;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 71.570973,98.461729 c 0,0 -1.488872,-0.259002 -1.858879,0.108387 -0.370008,0.367365 -1.855921,8.803524 -2.087914,10.561054 -0.232004,1.75753 -0.317164,4.00401 -0.21439,4.57487 -0.0101,0.69988 0.368241,0.94326 0.425821,0.87746 l 2.28173,0.0661 z"
id="path4314" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#949698;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 70.569596,98.755149 c -0.01773,0.296004 -2.199529,10.870271 -2.261203,12.170581 -0.06165,1.30032 0.31072,3.21606 -0.04462,3.3799 -0.355341,0.16388 -0.58306,0.25519 -0.735312,-0.10509 -0.108622,-0.33037 -0.368848,-3.11368 -0.195605,-4.29506 0.173278,-1.18137 2.158786,-10.80624 2.308544,-11.237029 0.1758,-0.417689 0.943147,-0.300638 0.928197,0.08671 z"
id="path4316" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#030007;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 67.575413,114.75396 c 0.299185,-0.26682 2.82104,0.0248 2.353274,0.28766 0.120388,-0.26164 -0.966148,21.16968 -0.966148,21.16968 -0.321588,0.36161 -2.280894,0.44599 -2.635973,-0.47617 0,0 -1.282502,-15.46808 1.248847,-20.98117 z"
id="path4318" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#b1b2b4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 68.272455,115.00255 -0.70333,-0.21676 c 0,0 -1.300892,3.31288 -1.377256,5.4827 -0.328426,2.27648 -0.20179,14.32772 0.160056,15.10817 0.273845,0.59063 0.484536,0.54577 0.731208,0.47308 -0.132143,-3.43844 0.03675,-14.49501 0.374434,-15.6526 0.153609,-1.62495 0.68015,-3.65239 0.814888,-5.19459 z"
id="path4320" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4507);fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 107.5756,94.192672 c 0,0 0.90781,-43.268534 0.68191,-45.181422 -1.23023,0.241078 -22.726413,4.189946 -22.726413,4.189946 l -4.467392,43.50272 z"
id="path4499" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#09070f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291663;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 109.94226,48.671364 -0.56089,45.497671 c 0,0 -30.495458,2.831185 -31.186916,3.006854 -0.69148,0.175669 -0.330722,1.017048 -0.330722,1.017048 0,0 3.202242,-0.321591 9.419245,-0.885974 6.217003,-0.564383 17.969613,-1.84224 19.607953,-2.010433 1.63836,-0.168196 2.42368,-0.2397 2.42368,-0.239697 0,0 -0.0771,4.872482 -0.0771,5.238777 0,0.0959 -0.13927,0.17936 -0.33983,0.25184 -10.390275,0.59447 -26.633856,1.69783 -31.4436,2.93281 -0.231992,0.29072 -0.491949,10.20583 -0.491949,10.20583 0.281625,0.15497 5.423843,-1.26531 11.011807,-1.74462 15.335252,-1.64639 19.804012,-1.00499 21.344882,-5.71529 0.91571,-5.42145 1.34517,-20.494631 1.34517,-20.494631 l 0.35136,-36.858539 z"
id="path4322" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#6f7073;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 77.411868,103.91325 c 0,0 1.063145,-0.6709 1.25419,-0.22612 0.191046,0.44478 -0.197257,7.59674 -0.176508,8.09945 0.02079,0.50271 0.147433,0.95122 -0.09758,1.2222 -0.245028,0.27098 -0.766213,0.31957 -1.042395,0.35134 -0.276182,0.0318 -0.05402,-8.63206 0.06224,-9.44687 z"
id="path4324" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#46484a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 78.97546,112.67054 c 0,0 0.328086,-8.68441 0.894951,-9.05631 0.250018,-0.26677 20.531119,-2.23686 29.085419,-2.70407 0,0 0.67902,0.79611 0.26789,3.34145 -0.28087,1.89737 -1.32214,3.85795 -2.26857,4.46833 0,0 2.35786,-2.02018 2.04222,-7.09216 -0.24294,-1.24276 -16.11566,1.25585 -16.11566,1.25585 -0.9444,0.13002 -3.9837,8.44222 -4.182038,8.64141 -7.716949,0.30636 -9.975475,2.07833 -9.724212,1.1455 z"
id="path4326" />
<ellipse
style="color:#000000;overflow:visible;vector-effect:none;fill:#d95340;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
id="path4328"
cx="83.578178"
cy="105.82099"
rx="0.56089103"
ry="0.5533585" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#d95340;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.32291675;stroke-miterlimit:2;paint-order:markers stroke fill"
d="m 82.958575,106.18016 c -0.609008,-0.63796 -1.992334,0.66651 -1.190515,0.73933 0.241749,0.007 0.367914,-0.30147 0.667075,-0.36694 0.218751,-0.0493 0.405768,0.18468 0.304921,0.35634 -0.450027,0.60808 -0.52823,0.84153 -0.844167,1.0729 -0.342452,0.21496 -0.898548,-0.16695 -0.819023,0.5888 0.03007,0.27606 1.131107,0.33876 1.658155,-0.54686 0.210475,-0.32253 0.80175,0.0775 0.588739,0.34142 -0.19038,0.31417 -0.567977,0.48775 -0.515963,0.88076 -0.0052,0.25699 0.426881,0.2478 0.558629,0.0624 0.657588,-0.72321 1.318084,-1.43322 0.407796,-1.74455 0.561929,-1.11103 0.816182,-0.17457 1.415261,-1.56037 0.157536,-0.3471 -0.41929,-0.48303 -0.450941,-0.26601 -0.46683,0.97779 -1.363227,0.8736 -1.779967,0.4428 z"
id="path4330" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4332);fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 123.49758,49.067522 c 0,0 -0.0705,53.468648 -0.75764,56.936138 -1.16535,6.57928 -2.63078,11.73021 -8.70444,14.39287 7.92002,-1.50118 27.53396,-6.01221 28.28571,-9.65942 0.55208,-11.401498 -0.27021,-58.432029 -0.27021,-58.432029 0,0 -14.7388,-3.295701 -18.55342,-3.237559 z"
id="path4309" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#4e5457;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="M 78.30836,54.454564 70.432643,98.331526 71.2757,98.383852 78.666579,54.29057 Z"
id="path4334" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#70757c;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 124.8123,72.186612 0.85382,1.931306 -0.85382,2.370025 1.91393,-2.370025 z"
id="path4488" />
<path
inkscape:connector-curvature="0"
id="path4490"
d="m 107.41661,73.119557 -0.85382,1.931306 0.85382,2.370025 -1.91393,-2.370025 z"
style="color:#000000;overflow:visible;vector-effect:none;fill:#70757c;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill" />
<path
inkscape:connector-curvature="0"
id="path4509"
d="m 107.37833,95.267241 -26.511892,2.511244 c -0.135763,0.721764 -0.424341,1.755042 1.875312,1.852584 3.500617,0.148482 18.61654,-0.846935 23.27085,-2.164032 1.36306,-0.385724 1.46754,-1.608614 1.36573,-2.199796 z"
style="color:#000000;overflow:visible;vector-effect:none;fill:url(#linearGradient4511);fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#5b585b;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 78.284745,97.100947 c 0.680588,-14.4694 3.333553,-29.668628 5.470204,-44.347429 l 0.889389,-0.176348 c -2.502774,14.715793 -5.552664,34.507894 -5.612737,44.100552 z"
id="path4513" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#5b585b;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="M 80.725112,96.438914 C 81.357027,81.702915 83.4597,67.618893 84.828255,53.20944 83.659178,67.637017 81.570622,81.500782 81.343904,96.506198 Z"
id="path4515" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#52565e;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 106.78688,97.624749 v 0.980036 h -0.98004 v 0.489104 h 0.98004 v 0.980031 h 0.48913 v -0.980031 h 0.98002 v -0.489104 h -0.98002 v -0.980036 z"
id="rect4517" />
<rect
style="color:#000000;overflow:visible;vector-effect:none;fill:#52565e;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
id="rect4522"
width="2.7589374"
height="0.51933014"
x="78.916763"
y="100.49229" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 90.251984,108.80352 -1.294175,-0.0345 1.566199,-3.31249 1.344012,-0.0542 z"
id="path4524" />
<path
inkscape:connector-curvature="0"
id="path4528"
d="m 96.80332,107.91957 -1.294174,-0.0345 1.566199,-3.31249 1.344011,-0.0542 z"
style="color:#000000;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill" />
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.54999999, 3.29999996;paint-order:markers stroke fill"
d="m 103.35466,107.21316 -1.29418,-0.0345 1.5662,-3.31248 1.34401,-0.0543 z"
id="path4530" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Leaders"
style="display:inline">
<text
xml:space="preserve"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
x="54.122028"
y="28.876167"
id="text4534"><tspan
id="tspan4532"
x="54.122028"
y="28.876167"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001">Button 0</tspan></text>
<text
id="text4538"
y="30.384899"
x="151.17892"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001"
y="30.384899"
x="151.17892"
id="tspan4536">Button 1</tspan></text>
<text
xml:space="preserve"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
x="130.88269"
y="18.324669"
id="text4542"><tspan
id="tspan4540"
x="130.88269"
y="18.324669"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001">Button 2</tspan></text>
<text
id="text4546"
y="80.354729"
x="31.912523"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001"
y="80.354729"
x="31.912523"
id="tspan4544">Button 3</tspan></text>
<text
xml:space="preserve"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
x="29.855825"
y="99.495857"
id="text4550"><tspan
id="tspan4548"
x="29.855825"
y="99.495857"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001">Button 5</tspan></text>
<text
id="text4554"
y="111.76219"
x="29.400412"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001"
y="111.76219"
x="29.400412"
id="tspan4552">Button 6</tspan></text>
<text
xml:space="preserve"
style="color:#000000;font-weight:900;font-size:4.23333359px;line-height:3.17500019px;font-family:Lato;-inkscape-font-specification:'Lato, Heavy';text-align:center;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;overflow:visible;vector-effect:none;fill:#d7252a;fill-opacity:1;stroke-width:0.55000001;stroke-dasharray:0.55000001, 3.30000008;paint-order:markers stroke fill"
x="173.11214"
y="85.690308"
id="text4558"><tspan
id="tspan4556"
x="173.11214"
y="85.690308"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;stroke-width:0.55000001">Button 4</tspan></text>
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="M 63.124178,31.772128 94.291591,60.577023"
id="path4345"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="M 127.00716,22.400186 113.88429,65.198573"
id="path4347"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="M 146.57607,34.065047 128.58942,63.193353"
id="path4349"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="m 160.61332,85.397431 -56.88611,8.243402"
id="path4351"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="m 44.225079,81.803153 30.802392,13.92351"
id="path4353"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="M 41.803519,98.888778 63.738687,103.0855"
id="path4355"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="color:#000000;overflow:visible;vector-effect:none;fill:none;stroke:#000000;stroke-width:0.5291667;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;paint-order:markers stroke fill"
d="m 41.540072,110.21938 20.868867,4.82739"
id="path4357"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:url(#linearGradient4562-2);fill-opacity:1;stroke:none;stroke-width:0.2822223"
d="m 156.02856,154.56715 -0.83645,1.44908 -0.83644,1.44822 h 0.95396 v 3.0632 l 0.71893,-0.41476 0.71892,0.41476 v -3.0632 h 0.95396 l -0.83644,-1.44822 z"
id="path4556"
inkscape:connector-curvature="0" />
<path
style="fill:url(#linearGradient4623-2);fill-opacity:1;stroke:none;stroke-width:0.2822223"
d="m 156.02855,175.12243 -0.83645,-1.44908 -0.83643,-1.44822 h 0.95394 v -3.06321 l 0.71893,0.41477 0.71892,-0.41477 v 3.06321 h 0.95396 l -0.83645,1.44822 z"
id="use4558"
inkscape:connector-curvature="0" />
<text
id="text4505"
y="159.06049"
x="161.79926"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333359px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.2822223"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333359px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.2822223"
y="159.06049"
x="161.79926"
id="tspan4507">Button7</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333359px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.2822223"
x="161.80814"
y="173.68317"
id="text4509"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333359px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.2822223"
id="tspan4511"
x="161.80814"
y="173.68317">Button8</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,335 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
viewBox="0 0 750.00004 749.99998"
height="750"
width="750"
sodipodi:docname="logitech-mx_master.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview55"
showgrid="false"
inkscape:zoom="0.90533333"
inkscape:cx="394.54153"
inkscape:cy="346.39586"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs4">
<linearGradient
id="linearGradient5204">
<stop
style="stop-color:#868686;stop-opacity:1;"
offset="0"
id="stop5206" />
<stop
style="stop-color:#868686;stop-opacity:0;"
offset="1"
id="stop5208" />
</linearGradient>
<linearGradient
id="linearGradient5128">
<stop
style="stop-color:#3a3a3a;stop-opacity:1"
offset="0"
id="stop5130" />
<stop
style="stop-color:#aaaaaa;stop-opacity:1"
offset="1"
id="stop5132" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient5128"
id="linearGradient3078"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
x1="230.63638"
y1="432.30179"
x2="238.061"
y2="447.85815" />
<linearGradient
xlink:href="#linearGradient5204"
id="linearGradient3080"
gradientUnits="userSpaceOnUse"
x1="196.63423"
y1="468.17209"
x2="170.13423"
y2="402.67206" />
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Device">
<g
id="layer1-0"
transform="matrix(1.066667,0,0,1.066667,557.63834,-227.02703)"
style="display:inline">
<g
style="stroke-width:1.03775251"
id="g3058"
transform="matrix(0.6738802,0,0,0.67794969,-190.55606,295.44166)">
<path
inkscape:connector-curvature="0"
id="path5084"
transform="translate(-522.78594,-97.359255)"
d="m 921.14258,351.92188 c -10.71472,0.3561 17.48242,40.65039 17.48242,40.65039 l -0.99805,38.58007 c -0.0632,-0.10181 -0.1163,-0.2052 -0.18164,-0.30664 -0.41273,0.4635 -0.8827,0.9276 -1.47656,1.39063 C 883.92622,472.81347 836.5,478.32226 756.5,516.32227 c -80,37.99997 -316.69239,159.29807 -343.5,147.5 -0.19217,-0.0846 -0.3462,-0.18445 -0.50195,-0.28321 -0.14711,0.0864 -0.35538,0.19871 -0.49805,0.28321 -0.0138,-0.0118 -0.0272,-0.0234 -0.041,-0.0352 l -0.0273,0.0156 c 20.65212,21.99316 41.34778,28.42752 134.68945,6.01954 h 67.87891 c 0,0 31.685,6.41255 73,41.25 56.21397,47.40048 70.15272,37.94645 213.83008,7.3789 120.72766,-25.68496 98.22343,-76.56575 107.07816,-168.1289 5.6329,-58.24749 15.6725,-114.94915 -35.90824,-161 -31.61176,-28.22275 -46.12465,-37.57431 -51.35742,-37.40039 z"
style="fill:#433737;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5077"
transform="translate(-522.78594,-97.359255)"
d="m 766.6582,304.5 c -179.15881,0.002 -367.84961,155.86523 -367.84961,155.86523 -21.93235,32.98189 -41.23548,69.54864 -57.98242,109.60157 7.5036,28.04106 30.67382,59.21512 71.17383,93.85547 59.9519,-35.50497 512.63903,-236.02476 512.5,-244 95.7156,51.99999 -269.006,189 -269,189 -12.27104,5.04673 -14.55606,11.0677 -7.5,18 l 2.06445,1.76953 h 0.002 l 11.89062,10.1875 c -0.62249,0.15805 -1.26128,0.30706 -1.87305,0.48242 -47.26127,13.54738 -84.55325,23.64795 -114.41015,30.79101 L 615,669.82227 l 63.40625,-16.95508 38.59961,33.06445 c 38.18376,34.64823 37.84255,32.06806 141.42187,14.14258 C 964.16532,681.77523 962.3307,680.80807 974.39258,545.2168 984.45817,432.06647 1011.3318,377.81074 858.42773,320.35742 828.82733,309.23515 797.88772,304.49969 766.6582,304.5 Z"
style="fill:#3d3d3d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5079"
transform="translate(-522.78594,-97.359255)"
d="m 924.5,419.82227 c 0.13868,7.95534 -450.25292,207.4789 -512.00586,243.71484 0.15695,0.0995 0.31224,0.19994 0.50586,0.28516 26.80761,11.79809 263.5,-109.50001 343.5,-147.5 80,-38.00001 127.42622,-43.50878 179.46875,-84.08594 0.5964,-0.46501 1.06842,-0.93101 1.48242,-1.39649 -2.56726,-3.98332 -6.80221,-7.67699 -12.95117,-11.01757 z"
style="fill:#826c5e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251" />
<path
inkscape:connector-curvature="0"
id="path5101"
transform="translate(-522.78594,-97.359255)"
d="m 633.2832,328.9668 c -128.50884,43.87332 -234.47461,131.39843 -234.47461,131.39843 -21.86064,32.87406 -41.10756,69.31169 -57.8164,109.21094 l 0.008,-0.004 61.25,-46.25 c -0.31467,-30.27892 8.67871,-33.61166 108.5,-91 105.67745,-60.75512 109.87649,-54.6167 115.74609,-80.49805 1.83541,-8.09301 4.52898,-16.4514 6.78711,-22.85742 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5107"
transform="translate(-522.78594,-97.359255)"
d="m 640.70703,428.57422 c -3.04651,0.0756 -6.31444,0.73835 -9.96875,2.0918 -19.09188,7.07104 -141.89935,74.20682 -175.71484,98.99414 -48.59449,35.62053 -48.4375,14.14257 -48.4375,14.14257 l -4.24219,-20.85937 c 0,0 -0.0901,0.0489 -0.0937,0.0508 9.1e-4,0.11168 -10e-4,0.2157 0,0.32813 l -61.25,46.25 -0.008,0.004 c -0.0548,0.13093 -0.11124,0.25961 -0.16602,0.39063 7.5036,28.04104 30.67382,59.21512 71.17383,93.85547 0.14966,-0.0886 0.33959,-0.19447 0.49414,-0.28516 0.0169,-0.01 0.0397,-0.0213 0.0566,-0.0312 1.02546,-0.60112 2.16407,-1.25057 3.39844,-1.93945 0.2066,-0.11531 0.43415,-0.23971 0.64648,-0.35743 1.08032,-0.59888 2.2254,-1.22479 3.45118,-1.88476 0.32998,-0.17769 0.67334,-0.36095 1.01367,-0.54297 1.22538,-0.65535 2.51457,-1.33647 3.87109,-2.04687 0.32591,-0.17069 0.65104,-0.34183 0.98438,-0.51563 0.98003,-0.51099 2.03888,-1.05627 3.08203,-1.59375 1.50441,-0.77516 3.19823,-1.63034 4.83007,-2.45898 2.6812,-1.36148 5.48308,-2.77245 8.49219,-4.27149 1.45002,-0.72234 2.95192,-1.46789 4.47461,-2.2207 3.14575,-1.55527 6.43566,-3.16851 9.87696,-4.84766 1.7505,-0.85415 3.50304,-1.70917 5.32617,-2.59375 3.69907,-1.79476 7.57491,-3.665 11.55664,-5.57812 1.62203,-0.77935 3.19102,-1.53607 4.85742,-2.33399 4.85137,-2.32297 9.91021,-4.73306 15.11328,-7.20312 1.05862,-0.50256 2.06054,-0.98002 3.13281,-1.48828 6.27234,-2.97314 12.74159,-6.02841 19.44532,-9.18164 0.19493,-0.0917 0.37504,-0.1777 0.57031,-0.26954 0.88374,-0.4156 1.84183,-0.86083 2.73242,-1.27929 8.89106,-4.17765 18.33343,-8.58591 27.83008,-13.01563 9.48674,-4.42512 19.20352,-8.94432 29.15625,-13.5625 5.63004,-2.6124 11.17539,-5.18811 16.91992,-7.84765 11.03955,-5.11098 22.24511,-10.28776 33.57227,-15.51563 4.59686,-2.12162 9.06381,-4.18813 13.6875,-6.32031 31.79772,-14.66333 64.04275,-29.4992 94.89648,-43.72656 0.64347,-0.29672 1.23671,-0.57103 1.87891,-0.86719 -0.0661,-2.523 -0.5325,-5.27289 -1.4043,-8.3125 -2.95973,-10.3194 -36.14133,-35.93502 -56.06055,-50.55859 C 663.08118,438.83704 654.18972,428.94451 642,428.57812 c -0.42664,-0.0128 -0.85775,-0.0147 -1.29297,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
transform="matrix(0.89707316,-0.44188205,0.39545007,0.91848747,0,0)"
ry="4.5092516"
rx="4.7671914"
y="299.94894"
x="-63.730179"
height="22.140448"
width="42.955582"
id="rect5118"
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.48045075;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5120"
d="m 275.08906,417.33778 4.375,22.875 80.75,-60.625 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5122"
d="m 281.58906,443.33778 91.75,-68.625 c 10.87423,-8.13345 34.03844,-10.26653 -9.25,21.375 -37.38734,27.32814 -82.5,47.25 -82.5,47.25 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5124"
d="m 197.58906,448.96278 c 6.125,13 10.625,29.125 10.625,29.125 0,0 57.34269,-25.16319 68.25,-30.75 -0.13843,-9.48681 -3.52264,-22.72856 -8.375,-27.875 -27.125,3.75 -70.5,29.5 -70.5,29.5 z"
style="fill:url(#linearGradient3078);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.47948301;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5138"
d="m 3.47828,341.26173 c 0,0 6.886406,9.46214 7.95495,30.22881 -9.7125082,0.38797 -22.45064,-1.59098 -48.96714,10.78339 -26.5165,12.37437 -35.70889,37.29989 -35.70889,37.29989 l -6.84404,-0.46967 -8.1731,-22.75242 c 0,0 5.196794,-22.7334 30.485095,-40.41753 C -32.486544,338.25007 3.47828,341.26173 3.47828,341.26173 Z"
style="fill:#797979;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.47948277px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5140"
transform="translate(-522.78594,-97.359255)"
d="m 527.89648,441.94336 c -11.21543,-6.8e-4 -35.91089,1.15173 -54.02148,10.37891 -20.66776,10.53002 -34.76604,36.66892 -38.41016,44.00195 l 7.17383,19.9707 c 2.6388,-7.65898 11.92913,-28.82418 37.36133,-42.34765 27.46537,-14.60461 48.83613,-10.8705 53.86328,-9.67383 -1.11415,-11.22385 -3.86953,-18.48609 -5.74414,-22.32617 -0.0929,-1.7e-4 -0.12786,-0.004 -0.22266,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251" />
<path
inkscape:connector-curvature="0"
id="path5145"
transform="translate(-522.78594,-97.359255)"
d="m 485.25195,479.63281 c -26.5165,12.37437 -35.70886,37.34486 -35.70886,37.34486 9.75656,-6.29912 84.5483,-48.37571 84.5483,-48.37571 -6.04962,0.7682 -22.32294,-1.34352 -48.83944,11.03085 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251" />
<path
inkscape:connector-curvature="0"
id="path5151"
d="m -6.1035156,230.91992 c -19.3024674,3.60682 -35.0488854,16.31894 -52.6556354,24.21599 -51.094769,27.0536 -101.437299,55.94388 -149.051399,88.65901 -9.95415,5.51243 -22.54214,11.99271 -33.83984,6.61914 -6.38959,-3.90926 -7.96324,-11.94005 -8.66992,-18.82617 -15.28799,12.40039 -32.51253,23.07504 -46.6875,36.30469 11.43671,32.54466 37.53518,57.07166 61.90234,80.5625 1.79409,1.58773 4.14015,-3.28155 6.15485,-2.80815 C -144.1825,402.09598 -56.798635,363.92186 29.448769,323.50255 46.66114,315.61589 63.86767,307.71041 80.912109,299.46484 75.326356,287.31278 62.865961,280.7519 53.502952,271.87742 35.5688,257.98999 18.22755,242.94827 -1.484375,231.63672 c -1.4916064,-0.46547 -3.0527704,-0.75113 -4.6191406,-0.7168 z"
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5162"
d="m -28.414062,137.02148 c -76.907488,29.50803 -148.819988,71.80459 -213.308758,122.89206 -13.55128,17.43946 -23.11685,37.54603 -33.88323,56.82187 -3.7754,7.32186 -7.34192,14.58222 -10.84707,22.04584 11.21464,-8.37958 22.86793,-16.47415 33.20898,-25.8125 -0.25698,-17.631 11.68533,-33.06792 26.42383,-41.59375 31.52229,-22.08766 66.11652,-39.23093 99.04413,-59.05073 30.395219,-17.37588 61.961588,-32.92482 91.295711,-52.0313 6.692064,-6.28955 7.910236,-15.49613 9.814453,-23.93359 l -0.935164,0.35421 z"
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5173"
d="m 152.77364,310.2307 c 1.1582,6.05599 2.3164,12.11198 3.4746,18.16797 21.37631,-16.04948 42.75261,-32.09896 64.12891,-48.14843 -22.5345,9.99349 -45.06901,19.98697 -67.60351,29.98046 z"
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5187"
d="m 261.2834,263.28539 c -12.21657,2.16029 -20.42211,12.86093 -30.56476,19.12846 -18.40968,13.8199 -38.36778,28.59535 -55.81414,41.82076 29.28272,-15.22709 58.48771,-31.62916 82.88671,-54.0625 1.70896,-1.96865 4.73868,-4.48833 4.69532,-6.85547 -0.39767,-0.0641 -0.80252,-0.0596 -1.20313,-0.0312 z"
style="display:inline;fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5192"
d="m 42.546875,449.04102 c 19.339052,15.73498 36.723013,34.10436 57.603515,47.67578 20.60808,9.36671 43.55773,2.08926 64.83959,-0.49809 35.57938,-6.15258 71.49952,-11.18454 106.39931,-20.59787 15.04923,-4.60526 29.72058,-14.93837 34.46618,-30.81811 9.43121,-25.52623 9.54274,-53.05503 12.87313,-79.81517 -0.62149,-4.24546 3.55982,-14.72991 -0.52003,-14.51534 -91.88723,32.85626 -183.77446,65.71253 -275.661695,98.5688 z"
style="display:inline;fill:url(#linearGradient3080);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="rect5212"
d="m -27.103516,182.32422 c -10.397754,4.71799 -21.409505,9.91406 -30.929687,15.4375 2.508683,3.97971 3.88786,8.5168 5.707031,12.72266 10.007293,-5.84796 21.032198,-9.89858 31.039063,-15.81641 -1.598593,-4.02995 -3.118058,-9.77197 -5.816407,-12.34375 z"
style="display:inline;fill:#868686;fill-opacity:1;stroke:none;stroke-width:1.03775251"
transform="translate(124.57988,108.29077)" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Leaders">
<text
id="text4473"
y="565.3598"
x="102.38671"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="565.3598"
x="102.38671"
id="tspan4475">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="108.10234"
y="242.15002"
id="text4477"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
id="tspan4479"
x="108.10234"
y="242.15002">Button1</tspan></text>
<text
id="text4481"
y="371.8588"
x="100.09487"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="371.8588"
x="100.09487"
id="tspan4483">Button2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="653.47821"
y="157.51355"
id="text4485"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
id="tspan4487"
x="653.47821"
y="157.51355">Button3</tspan></text>
<text
id="text4489"
y="93.571732"
x="449.42313"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="93.571732"
x="449.42313"
id="tspan4491">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="448.09875"
y="620.54236"
id="text4493"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
id="tspan4495"
x="448.09875"
y="620.54236">Button5</tspan></text>
<text
id="text4497"
y="123.03238"
x="209.7597"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"
transform="scale(0.99699417,1.0030149)"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696"
y="123.03238"
x="209.7597"
id="tspan4499">Button6</tspan></text>
<path
inkscape:connector-curvature="0"
id="path3082"
d="m 162.38897,251.08006 123.99755,90.72462"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3084"
d="m 166.48807,366.54776 151.6664,-7.21673"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3086"
d="M 154.19079,550.05892 287.41129,438.71507"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3088"
d="M 274.08923,125.30276 410.38405,310.87584"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3092"
d="m 487.24203,102.62161 83.00662,283.51442"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3094"
d="M 694.24619,166.54122 625.5864,361.39295"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path3096"
d="m 502.61363,600.57604 87.10572,-89.69366"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,445 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
viewBox="0 0 750.00004 749.99998"
height="750"
width="750"
sodipodi:docname="roccat-kone-xtd.svg"
inkscape:version="0.92+devel 15739 custom">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview91"
showgrid="false"
inkscape:zoom="1.2803347"
inkscape:cx="378.62971"
inkscape:cy="438.51164"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer2" />
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="https://opensource.org/licenses/MIT" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Device"
style="display:inline">
<g
id="layer1-5"
transform="matrix(1.066667,0,0,1.066667,557.63834,-227.02703)"
style="display:inline">
<g
style="stroke-width:1.08492351"
id="g3136"
transform="matrix(0.63485207,0,0,0.63485207,-238.79655,274.87627)">
<path
inkscape:connector-curvature="0"
id="path4770"
d="m -6.8766439,519.77381 c -32.5046101,10.85914 -64.2932331,9.07935 -55.9542041,-23.77308 18.883288,-74.39257 -57.845532,2.41084 -29.233145,-133.3763"
style="fill:none;stroke:#000000;stroke-width:32.00106812;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3661"
d="m -33.934887,422.04568 10.14038,-25.10953 C 52.122953,323.19727 160.74504,269.07207 269.83981,256.48052 c 114.24665,-13.18617 232.89306,-1.04277 284.3675,72.85307 67.68352,97.16539 16.07476,170.11753 -8.69176,195.56454 -20.05502,20.60604 -39.26023,38.76732 -57.46217,50.70193 -38.08063,24.96863 -99.02413,29.12078 -118.30443,27.5239 -56.28478,-4.66179 -227.65266,41.307 -235.6432,46.83891 L 32.219046,607.9527 C 4.8894737,559.61921 -21.751345,509.50644 -33.934887,422.04568 Z"
style="fill:#293843;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4463"
d="m 520.63342,372.91486 c -22.02158,0.11026 -45.15654,9.22867 -63.99943,19.07328 -68.64532,35.8642 -269.2094,153.12888 -338.02986,180.28255 l -87.122352,34.37512 c 0.245863,0.43536 0.49112,0.87206 0.737105,1.30711 l 39.216027,16.16965 c 44.83999,-15.41316 98.86516,-40.41176 154.72423,-67.21674 90.48008,-43.41854 177.45369,-92.45774 236.96271,-121.89569 60.39622,-29.87684 105.87888,-24.18751 112.83284,44.85426 6.15884,-13.91293 10.75607,-30.17964 11.63778,-48.45529 -13.44827,-44.58801 -39.32739,-58.63259 -66.95905,-58.49425 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4468"
d="m 460.17444,405.06363 c -25.33816,12.5814 -164.20311,89.16529 -247.36725,132.94909 -31.24494,16.55348 -62.91668,32.44366 -95.5461,46.08015 l 3.13236,9.65662 c 54.85379,-22.99389 108.07344,-49.78006 161.39646,-76.09146 64.31558,-32.64428 127.12882,-68.2385 192.32459,-99.13545 18.32983,-7.64259 38.30614,-12.8303 58.27155,-10.58417 14.47996,1.85097 28.06901,9.59531 37.24885,20.96153 6.66994,-53.74538 -76.10417,-40.33748 -109.46046,-23.83631 z"
style="fill:#00ff3a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4545"
d="m 270.88842,559.80819 26.12051,4.09732 62.14289,-30.90074 c 11.97455,-20.17142 5.93562,-23.53024 5.29239,-31.92505 l -91.50713,47.4608 c -3.16993,2.58552 -6.42443,5.13123 -2.04866,11.26767 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4547"
d="m 392.10122,486.05615 c 1.23298,4.69552 4.04803,7.598 -1.19506,19.63307 l -9.73117,17.58438 80.75159,-31.4129 c 5.77716,-10.78358 11.4074,-21.61616 11.4384,-34.31516 -2.7867,-11.40006 -8.20083,-9.22506 -13.65779,-6.82888 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4549"
d="M 20.837165,461.33753 26.414193,480.9345 62.94875,466.25238 55.307676,431.63187 Z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4551"
d="m 178.69842,365.35554 12.29201,31.24217 56.50906,-25.09617 -12.46274,-27.48628 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4553"
d="m 261.4987,335.64987 11.95056,26.63267 49.85089,-20.31594 12.80416,-3.41445 -6.82888,-14.16994 -12.97489,-3.41445 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
d="m 204.43745,364.0435 2.09895,5.60714 5.81901,-2.56255 0.64062,1.71134 -5.81901,2.56254 2.09895,5.60714 -1.75511,0.77292 -2.09894,-5.60715 -5.81902,2.56255 -0.64059,-1.71135 5.81898,-2.56254 -2.09892,-5.60714 z"
id="path4560"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351"
id="path4567"
d="m 305.42303,329.94388 4.03768,8.95391 -2.72436,1.22853 -4.03769,-8.95391 z" />
<path
inkscape:connector-curvature="0"
d="m 46.989112,448.7916 2.557622,11.39542 -2.682847,1.56354 -2.557622,-11.39545 z"
id="path4569"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351"
id="path4577"
d="m 42.643233,451.50777 2.557622,11.39545 -2.682847,1.56351 -2.557622,-11.39545 z" />
<path
inkscape:connector-curvature="0"
d="m 38.478433,454.34466 2.557622,11.39543 -2.682847,1.56354 -2.557622,-11.39545 z"
id="path4579"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4581"
d="m 119.43841,465.4441 5.37199,3.74229 1.87114,-8.26926 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4583"
d="m 99.218,376.23286 -2.29366,6.51884 6.33774,-3.25942 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4585"
d="m 370.13999,299.12951 c -0.43414,-0.004 -0.88599,0.004 -1.35658,0.0243 -114.61991,18.29248 -262.7613,57.8235 -362.6396132,162.97056 l -0.2413441,18.34924 -23.0804397,18.75305 c 0.295394,0.96107 0.592605,1.91666 0.892085,2.8672 L 6.8682998,485.78508 11.938416,498.5815 c 3.022522,1.91455 4.542353,4.99753 13.03731,2.65575 0,0 35.049508,-13.87527 66.878294,-31.62836 25.86269,-14.4254 169.13513,-92.29377 297.45122,-135.68783 3.53168,-1.85807 6.92052,-3.82383 2.89753,-11.3479 l -11.34789,-17.38339 c -1.68431,-3.27833 -4.20267,-6.0005 -10.71489,-6.06024 z m 0.85055,7.18994 c 0.76127,-0.0183 1.49621,0.14715 2.1413,0.68389 2.28062,2.60105 3.95393,5.73706 5.90572,8.6044 2.36789,3.85426 5.13602,7.51375 7.31692,11.43239 -2.00889,0.76437 -4.02217,1.5172 -6.0383,2.2622 -74.38121,26.47497 -146.51346,58.91354 -216.93155,94.53357 -23.7859,11.80119 -47.13201,24.45131 -70.49007,37.07193 -21.87976,12.03816 -44.368571,22.99172 -67.494965,32.39674 -2.178032,0.79387 -4.91012,2.49014 -7.139522,0.97798 -2.462342,-3.62775 -3.065109,-8.18739 -5.10326,-12.05744 -0.191754,-5.72806 0.125694,-11.45575 0.125574,-17.18406 19.24401,-19.99827 40.662677,-37.85032 63.501803,-53.60899 56.88977,-39.14613 121.81546,-65.28367 188.25625,-83.14833 34.45174,-9.02055 69.30996,-16.66573 104.56505,-21.77335 0.46215,-0.10291 0.9283,-0.17995 1.38505,-0.19093 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4590"
d="m 69.56866,436.43193 c 2.34022,-18.39325 11.0874,-31.41629 35.56456,-46.25604 24.47717,-14.83973 51.02774,-12.17822 62.53237,-11.10613 4.19739,0.39116 6.14741,2.1271 9.65751,8.20888 l 9.65751,18.10785 c -9.72905,-3.24303 -45.31306,0.55135 -63.36379,8.82104 -23.93977,10.96767 -32.63451,13.417 -49.78556,44.90031 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<text
transform="matrix(0.81792144,-0.30782972,0,1.2226113,0,0)"
id="text4751"
y="544.12469"
x="541.47949"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;stroke-width:1.08492351"
xml:space="preserve"><tspan
y="544.12469"
x="541.47949"
id="tspan4753"
style="font-size:19.26995659px;line-height:1.25;stroke-width:1.08492351">&gt;</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4759"
d="m 300.25264,556.5858 10.24335,-10.8622 0.29876,2.6035 -4.75887,5.05767 6.35939,-0.96032 0.72556,2.19804 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<path
inkscape:connector-curvature="0"
id="path4761"
d="m 175.51398,404.23374 c -14.95857,0.0867 -38.3591,3.7713 -51.89715,9.97357 -23.8618,10.93194 -32.57995,13.40905 -49.62048,44.60172 l 112.98222,-53.41898 -0.0122,-0.008 c -2.4337,-0.80767 -6.47543,-1.17722 -11.45245,-1.14838 z"
style="fill:#151d23;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.08492351" />
<ellipse
ry="11.985341"
rx="11.98534"
cy="294.12094"
cx="-12.758862"
id="path4352"
style="display:inline;fill:#898989;fill-opacity:1;stroke:none;stroke-width:1.08492351"
transform="translate(124.57988,108.29077)" />
</g>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Leaders"
style="display:inline">
<text
id="text4473"
y="573.11182"
x="147.83389"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4217"
y="573.11182"
x="147.83389"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="147.83389"
y="593.82111"
id="text4212"><tspan
x="147.83389"
y="593.82111"
id="tspan4214"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button12</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="425.59845"
y="619.85443"
id="text4216"><tspan
x="425.59845"
y="619.85443"
id="tspan4218"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button3</tspan></text>
<text
id="text4220"
y="642.56366"
x="425.59845"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4222"
y="642.56366"
x="425.59845"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button15</tspan></text>
<text
id="text4238"
y="623.47388"
x="612.12598"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4240"
y="623.47388"
x="612.12598"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="612.12598"
y="644.18311"
id="text4242"><tspan
x="612.12598"
y="644.18311"
id="tspan4244"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button16</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 436.11779,601.86162 71.66472,-160.7027"
id="path3163"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 635.91034,602.58551 593.92495,397.00187"
id="path3165"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="578.06567"
y="124.26476"
id="text4258"><tspan
x="578.06567"
y="124.26476"
id="tspan4260"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button10</tspan></text>
<text
id="text4262"
y="145.71872"
x="578.06567"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4264"
y="145.71872"
x="578.06567"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button22</tspan></text>
<text
id="text4268"
y="80.422646"
x="374.27548"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4270"
y="80.422646"
x="374.27548"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button9</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="374.27548"
y="101.5351"
id="text4272"><tspan
x="374.27548"
y="101.5351"
id="tspan4274"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button21</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="233.21674"
y="657.15039"
id="text4278"><tspan
x="233.21674"
y="657.15039"
id="tspan4280"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button5</tspan></text>
<text
id="text4282"
y="677.85962"
x="233.21674"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4284"
y="677.85962"
x="233.21674"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button17</tspan></text>
<text
id="text4288"
y="459.87857"
x="113.53596"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4290"
y="459.87857"
x="113.53596"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button11</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="113.53596"
y="480.58783"
id="text4292"><tspan
x="113.53596"
y="480.58783"
id="tspan4294"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button23</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="97.079071"
y="317.79367"
id="text4340"><tspan
x="97.079071"
y="317.79367"
id="tspan4342"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button1</tspan></text>
<text
id="text4344"
y="339.46393"
x="97.079071"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4346"
y="339.46393"
x="97.079071"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button13</tspan></text>
<text
id="text4350"
y="203.12646"
x="170.02243"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4352"
y="203.12646"
x="170.02243"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="170.02243"
y="225.13828"
id="text4354"><tspan
x="170.02243"
y="225.13828"
id="tspan4356"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button14</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
x="234.68954"
y="108.61727"
id="text4360"><tspan
x="234.68954"
y="108.61727"
id="tspan4362"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button6</tspan></text>
<text
id="text4364"
y="130.57028"
x="234.68954"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666696"
xml:space="preserve"><tspan
id="tspan4366"
y="130.57028"
x="234.68954"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:1.06666696">Button18</tspan></text>
<path
inkscape:connector-curvature="0"
id="path3167"
d="M 263.10902,638.05592 383.99798,381.07636"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3171"
d="M 201.5787,551.18959 325.36322,445.50222"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3173"
d="M 184.20544,444.77834 329.70653,382.52413"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3175"
d="M 597.54438,152.32838 510.67805,292.76226"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3177"
d="m 413.67732,110.34298 33.29875,204.13587"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3179"
d="m 270.34788,142.91784 97.00073,180.24763"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3181"
d="M 221.12363,235.57527 376.03525,337.64321"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path3183"
d="m 176.96658,323.16547 131.02338,28.95545"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -1,482 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 750.00005 750"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="etekcity.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4449">
<stop
style="stop-color:#a6a6a6;stop-opacity:1"
offset="0"
id="stop4451" />
<stop
style="stop-color:#484848;stop-opacity:1"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4336">
<stop
style="stop-color:#898989;stop-opacity:1;"
offset="0"
id="stop4338" />
<stop
style="stop-color:#898989;stop-opacity:0;"
offset="1"
id="stop4340" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient3237"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-138.13637,564.60502)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4336"
id="linearGradient3889"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79176032,0,0,0.79176032,-529.7793,277.79557)"
x1="97.085503"
y1="74.08123"
x2="95.471596"
y2="200.83122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient3891"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-441.46063,314.40367)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4336"
id="linearGradient3921"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.79176032,0,0,0.79176032,-529.7793,277.79557)"
x1="97.085503"
y1="74.08123"
x2="95.471596"
y2="200.83122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient3923"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.344964,0,0,1.344964,-441.46063,314.40367)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.96038311"
inkscape:cx="377.27056"
inkscape:cy="338.13614"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="1920"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Device"
transform="translate(647.36582,-57.672087)"
style="display:inline">
<g
id="g3893"
transform="translate(121.82639,-21.866275)">
<g
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,192.05523)"
style="fill:#000000;fill-opacity:1;stroke:none;display:inline"
id="g4271">
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 421.23361,409.14757 c 4.4349,4.09496 9.16721,10.86185 32.57742,27.27412 4.08118,24.47294 2.40765,48.35999 1.01015,67.42768 -1.3975,19.06769 -9.52288,85.7367 -30.55711,85.7367 l -41.92133,-6.18719 8.9651,-171.72593 32.38801,-150.26019 27.05315,-2.27284 -2.70689,27.21098 -26.19294,53.47495 z"
id="path4249"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cczcccccccc" />
<use
style="fill:#000000;fill-opacity:1;stroke:none"
x="0"
y="0"
xlink:href="#path4249"
id="use4266"
transform="matrix(-1,0,0,1,580.95786,0)"
width="1469.2054"
height="1013.322" />
</g>
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4251"
d="m -268.43146,403.53037 c -1.07689,19.01234 -1.64984,38.40264 -3.69907,56.68573 -2.36798,4.75208 -4.96718,7.8857 -7.59809,10.79728 l -13.59657,0 5.59859,-67.18309 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4253"
d="m -281.12826,473.7127 -0.29993,6.19844 7.09822,5.79854 -2.19945,30.1924 -8.99773,9.59758 -0.29993,28.99271 -2.3994,3.59909 -14.59632,0 0,-84.47873 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
id="use4275"
xlink:href="#path4251"
y="0"
x="0"
style="display:inline" />
<ellipse
sodipodi:ry="36.875"
sodipodi:rx="57.5"
sodipodi:cy="231.07376"
sodipodi:cx="290.47894"
d="m 347.97894,231.07376 c 0,20.3655 -25.74362,36.875 -57.5,36.875 -31.75637,0 -57.5,-16.5095 -57.5,-36.875 0,-20.3655 25.74363,-36.875 57.5,-36.875 31.75638,0 57.5,16.5095 57.5,36.875 z"
ry="36.875"
rx="57.5"
cy="231.07376"
cx="290.47894"
id="path4243"
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1.26300848;stroke-opacity:1;display:inline"
transform="matrix(0.79176032,0,0,0.79176032,-628.41671,124.43258)" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-698.21665,-85.740335)"
id="use4277"
xlink:href="#path4253"
y="0"
x="0"
style="display:inline" />
<path
sodipodi:nodetypes="cccccscccccccccccccccccscccccc"
inkscape:connector-curvature="0"
id="path3441"
d="m -401.08313,328.79009 0.26444,-40.70143 c -39.18883,7.37119 -44.1411,4.0242 -51.69484,0.84743 -19.57977,14.34842 -45.06471,30.13362 -73.61979,38.63234 -2.47282,19.58198 -2.71663,46.75085 -2.09075,66.56663 19.0204,10.56139 17.6053,33.92046 19.25741,48.34377 1.65211,14.4233 7.20626,94.24576 7.20626,94.24576 l -2.59797,21.72393 23.30745,43.04888 c -0.16213,7.00604 -0.46719,14.87323 -3.03251,37.40758 -7.15647,2.04323 -13.81042,1.56652 -20.02442,-1.10259 0.0912,10.91499 -0.68305,21.82736 0.56908,32.68021 11.24444,13.4205 16.39645,27.09393 56.20571,56.18715 l 6.498,11.63207 c 13.0739,7.46592 23.16933,11.65186 42.40866,14.95221 19.23933,-3.30035 29.33476,-7.48629 42.40866,-14.95221 l 6.498,-11.63207 c 39.80926,-29.09322 44.96127,-42.76665 56.2057,-56.18715 1.25213,-10.85285 0.47635,-21.76522 0.56754,-32.68021 -6.214,2.66911 -12.86641,3.14582 -20.02288,1.10259 -2.56532,-22.53435 -2.87037,-30.40154 -3.0325,-37.40758 l 23.3059,-43.04888 -2.59642,-21.72393 c 0,0 5.55415,-79.82246 7.20625,-94.24576 1.65211,-14.42331 0.23546,-37.78238 19.25586,-48.34377 0.62589,-19.81578 0.38362,-46.98465 -2.08919,-66.56663 -28.55509,-8.49872 -54.04157,-24.28392 -73.62134,-38.63234 -7.55373,3.17677 -12.50447,6.52376 -51.69329,-0.84743 l 0.26444,40.70143 z"
style="fill:#282828;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4289"
d="m -398.45459,328.52925 0,117.85034"
style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<path
sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
id="path4247"
d="m -390.51793,495.35976 13.14911,20.077 24.31724,0 -19.22802,-64.1898 -26.14665,-13.56354 -26.14819,13.56354 -19.22802,64.1898 24.31879,0 13.14909,-20.077 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
<rect
ry="3.2500002"
rx="3.2500002"
y="334.18024"
x="-410.93967"
height="59.523411"
width="25.025282"
id="rect4245"
style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1;stroke-opacity:1;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4311"
d="m -408.76059,297.49061 c -14.10207,2.39851 -28.95919,4.88556 -42.94836,0.51186 -20.52977,14.9081 -42.9383,27.51676 -67.08004,35.5287 -1.79569,18.70085 -2.21232,37.56904 -1.4629,56.27529 14.36611,10.46486 18.14376,29.44442 18.67596,46.17572 1.42879,19.10333 3.31403,38.21183 4.78767,57.33922 l 94.06329,0.0603 0,-99.67829 -5.64129,0 c -1.42556,0 -2.57322,-1.14766 -2.57322,-2.57323 l 0,-54.37631 c 0,-1.42556 1.14766,-2.57322 2.57322,-2.57322 l 2.21136,0 c -2.89117,-5.43908 -2.75569,-17.98166 -2.75569,-23.06002 0,-6.57742 0.14421,-9.08623 0.15,-13.63002 z"
style="fill:url(#linearGradient3921);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(-1,0,0,1,-796.64968,2.010815e-6)"
id="use4348"
xlink:href="#path4311"
y="0"
x="0"
style="display:inline" />
<circle
sodipodi:ry="13.13577"
sodipodi:rx="13.13577"
sodipodi:cy="194.21156"
sodipodi:cx="165.89903"
d="m 179.0348,194.21156 c 0,7.25469 -5.88108,13.13577 -13.13577,13.13577 -7.25468,0 -13.13577,-5.88108 -13.13577,-13.13577 0,-7.25468 5.88109,-13.13577 13.13577,-13.13577 7.25469,0 13.13577,5.88109 13.13577,13.13577 z"
r="13.13577"
cy="194.21156"
cx="165.89903"
id="path4352"
style="fill:#898989;fill-opacity:1;stroke:none;display:inline"
transform="matrix(0.79176032,0,0,0.79176032,-529.7793,210.17291)" />
<path
inkscape:connector-curvature="0"
id="path4357"
d="m -420.59834,454.5406 c -5.60675,18.71514 -11.21351,37.43027 -16.82027,56.1454 5.1217,0 10.2434,0 15.3651,0 4.38485,-6.69216 8.76766,-13.38566 13.15375,-20.077 6.98254,0 13.96508,0 20.94762,0 4.38609,6.69134 8.76889,13.38484 13.15374,20.077 5.12118,0 10.24237,0 15.36355,0 -5.60676,-18.71565 -11.21352,-37.43129 -16.82027,-56.14694 -7.39028,-3.83406 -14.78056,-7.66812 -22.17083,-11.50218 -7.39079,3.83457 -14.78159,7.66915 -22.17239,11.50372 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="use4396"
d="m -521.43644,406.56488 c -1.77374,0.0227 -3.15566,0.4222 -3.55518,1.76754 l 0.11752,2.1727 c 1.24058,16.62081 0.75876,33.65011 3.93561,49.99997 1.98359,2.87617 3.63732,8.09685 7.96709,7.20935 1.8046,-0.22471 4.69928,1.07511 6.16243,-0.0881 -0.0876,-1.12531 -0.18047,-2.37689 -0.26598,-3.46086 -1.38363,-12.51596 -2.3414,-25.11574 -3.33096,-37.70913 -0.77697,-6.57243 -2.15369,-13.39954 -5.30263,-19.41823 -1.9185,-0.16721 -4.00601,-0.49523 -5.7279,-0.4732 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="use4398"
d="m -506.09917,476.83515 c -1.97837,0.009 -3.95674,0.0188 -5.93511,0.0279 0.85216,4.85149 -4.04309,7.59388 -6.85213,10.37484 -0.6345,6.02214 1.09923,12.03757 0.98197,18.13626 0.3064,4.54843 -0.35793,10.2138 4.18921,12.95425 3.89072,2.9778 6.76537,7.60716 5.65521,12.64652 0.43285,7.84497 -0.8119,15.99277 0.9062,23.38167 1.01515,0.57035 2.08809,0.77358 3.18869,0.80413 l 2.20518,-18.43626 c 0,0 -2.26899,-32.57611 -4.33922,-59.88925 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4404"
d="m -271.77677,406.75044 c -3.09643,0.0485 -6.19285,0.0969 -9.28928,0.14537 -3.15953,5.97283 -4.55856,12.75131 -5.34747,19.29452 l -3.45931,41.48855 c 3.94759,0.0294 9.07538,1.78551 11.24547,-2.81911 5.80456,-6.57393 3.74439,-15.87475 4.98871,-23.78837 0.76732,-11.43639 1.23856,-22.86533 1.86188,-34.32096 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4406"
d="m -288.21508,476.67123 c -0.84134,0.006 -1.68687,0.0599 -2.53457,0.11907 -2.07117,27.32261 -4.3423,59.9341 -4.3423,59.9341 l 2.20826,18.47337 c 1.29581,-0.023 2.52331,-0.3133 3.58612,-1.2263 1.08603,-9.86486 -0.19804,-20.31797 0.95414,-30.09153 3.59307,-4.65204 10.46727,-8.17451 9.15627,-15.08365 0.31411,-7.28513 1.50719,-14.93066 1.3129,-22.00692 -3.27092,-2.21915 -7.90201,-5.21182 -6.84904,-9.77793 -1.14795,-0.27038 -2.31544,-0.34912 -3.49178,-0.34021 z"
style="fill:#898989;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
inkscape:connector-curvature="0"
id="path4441"
d="m -398.42702,334.8881 -2.54284,4.40528 -2.54281,4.40266 2.90008,0 0,9.31229 2.18557,-1.2609 2.18556,1.2609 0,-9.31229 2.90008,0 -2.54283,-4.40266 -2.54281,-4.40528 z"
style="fill:url(#linearGradient3923);fill-opacity:1;stroke:none;display:inline" />
<use
height="1013.322"
width="1469.2054"
transform="matrix(1,0,0,-1,-9.1690072e-7,727.78645)"
id="use4460"
xlink:href="#path4441"
y="0"
x="0"
style="display:inline" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,-57.672087)"
style="display:inline">
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M -346.88483,324.11711 -381.86206,206.36042"
id="path4211"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M -204.64408,314.78985 -143.68094,209.1986"
id="path4215"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -480.19795,353.09245 84.92794,58.46775"
id="path4227"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -481.9468,416.63443 92.50633,61.96547"
id="path4229"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -277.50576,447.94085 91.11706,-91.11705 75.50256,0"
id="path4546"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -110.92083,419.10931 -48.8358,0"
id="path4221"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -110.81855,476.81202 -50.8131,0"
id="path4225"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path4556"
d="m -95.10276,585.08945 -2.54284,4.40528 -2.54281,4.40265 2.90008,0 0,9.3123 2.18557,-1.2609 2.18556,1.2609 0,-9.3123 2.90008,0 -2.54283,-4.40265 -2.54281,-4.40528 z"
style="fill:url(#linearGradient3237);fill-opacity:1;stroke:none;display:inline" />
<use
style="display:inline"
height="1013.322"
width="1469.2054"
transform="matrix(1.0000001,0,0,-1.0000001,303.3243,982.46676)"
id="use4558"
xlink:href="#path4441"
y="0"
x="0" />
<text
xml:space="preserve"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-368.79688"
y="175.47208"
id="text4473"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-368.79688"
y="175.47208"
id="tspan4217"
style="font-size:32.00000381px">Button0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4477"
y="205.6097"
x="-141.6575"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="205.6097"
x="-141.6575"
id="tspan4479"
sodipodi:role="line"
style="font-size:32.00000381px">Button1</tspan></text>
<text
xml:space="preserve"
style="font-size:32.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-252.41873"
y="147.92294"
id="text4481"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4483"
x="-252.41873"
y="147.92294">Button2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4485"
y="361.82675"
x="-492.72778"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
y="361.82675"
x="-492.72778"
id="tspan4487"
sodipodi:role="line"
style="font-size:32.00000381px">Button3</tspan></text>
<text
xml:space="preserve"
style="font-size:31.67041588px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-492.44421"
y="414.9819"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="-492.44421"
y="414.9819"
style="font-size:32.00000381px">Button4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4493"
y="356.69751"
x="-110.46946"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="356.69751"
x="-110.46946"
id="tspan4495"
sodipodi:role="line"
style="font-size:32.00000381px">Button5</tspan></text>
<text
xml:space="preserve"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-110.46946"
y="416.97623"
id="text4497"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4499"
x="-110.46946"
y="416.97623"
style="font-size:32.00000381px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4501"
y="476.83734"
x="-110.46946"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="476.83734"
x="-110.46946"
id="tspan4503"
sodipodi:role="line"
style="font-size:32.00000381px">Button7</tspan></text>
<text
xml:space="preserve"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-77.532547"
y="605.11292"
id="text4505"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4507"
x="-77.532547"
y="605.11292"
style="font-size:32.00000381px">Button8</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4509"
y="650.02606"
x="-77.532547"
style="font-size:31.67041206px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="650.02606"
x="-77.532547"
id="tspan4511"
sodipodi:role="line"
style="font-size:32.00000381px">Button9</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="m -276.93036,342.77164 25.64997,0 0,-188.87707"
id="path4213"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

66
data/gnome/README.md Normal file
View File

@@ -0,0 +1,66 @@
libratbag gnome theme
====================
Requirements
------------
See the Logitech G403 for an example of a device with a small amount of buttons,
and the Logitech G700 for an example of a device with a large amount of buttons.
- Canvas size should be between 400x400 and 500x500 pixels.
- Three layers in the final SVG:
1. a lower layer named "Device" with the device itself. Each button on the
device should have an id `buttonX`, with `X` being the number of the button
(so for button 0 the id would be `button0`). Similarly, each LED on the device
should have an id `ledX`.
2. a middle layer named "Buttons" with the button leaders (see below for
leaders).
3. an upper layer named "LEDs" with the LED leaders.
- A leader line is a path that extends from the button or LED to the left or the
right of the device (see below). Each leader line requires the following:
- It should start with a 7x7 square placed on or close to the button or LED
that it maps with.
- From this square, a path should extend left or right (see below).
- Each path should end with a 1x1 pixel with identifier `buttonX-leader` (or
`ledX-leader`), where `X` is the number of the button (or LED) with
which the leader maps. For button 0, this would be `button0-leader`.
- All these elements should be grouped and given the identifier `buttonX-path`
(or `ledX-path` for LEDs)
- Leader lines should have a vertical spacing of at least 40 pixels. When there
are several leader lines above and below each other, make the spacing between
them equal.
- If the device's scroll wheel supports horizontal tilting, add two small arrows
left and right of the scroll wheel with the respective button identifiers (see
the Logitech G700 for an example). Do not cut the scroll wheel in half
vertically to map these buttons.
- If there aren't too many buttons, preferably make the leaders point to the
right with the device itself placed on the left. If the buttons would extend
below or above the device, make some point to the left instead with the device
itself centered in the middle. In this case, half of the leaders should extend
to the left and the other half to the right.
- When a leader points to the right, its 1x1 pixel should have a style property
`text-align:start`. When a leader points to the left, its 1x1 pixel should
have a style property `text-align:end`.
- The canvas should be resized so that there is a 20px gap between the device
and the edge of the canvas and no gap between the 1x1 pixels and the canvas.
Please note that due to the way the SVG is drawn, you cannot rely on the
z-ordering of elements to line up or cover elements (as noted in [this
issue](https://github.com/libratbag/piper/issues/48), which includes links to
examples). As such, please make sure that you align the elements appropriately;
[this
comment](https://github.com/libratbag/piper/issues/48#issuecomment-315979109)
includes some helpful tips.
Technique
---------
The simplest approach is to find a photo of the device and import it into
inkscape. Put it on the lowest layer, create a new layer "Device" above it
and start tracing the outlines and edges of the device. Fill in the shapes
and your device should resemble the underlying photo. Delete the photo
layer, add leaders in their respective layers and you're done.
Make sure the image looks ''toned-down'' and not realistic. Do not use dark or
bright colors.

View File

@@ -0,0 +1,410 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="417.20001"
height="407.25"
viewBox="0 0 417.20001 407.24999"
version="1.1"
id="svg8"
inkscape:version="0.91 r13725"
sodipodi:docname="logitech-g303.svg"
inkscape:export-filename="/home/jimmac/logitech-g403.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<inkscape:path-effect
effect="spiro"
id="path-effect4193"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4185"
is_visible="true" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="21.208975"
inkscape:cy="195.5613"
inkscape:document-units="px"
inkscape:current-layer="Device"
inkscape:document-rotation="0"
showgrid="false"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:pagecheckerboard="false"
showguides="true"
inkscape:window-width="1920"
inkscape:window-height="1101"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1"
fit-margin-top="20"
fit-margin-left="20"
fit-margin-bottom="20"
fit-margin-right="0"
inkscape:guide-bbox="true"
guidetolerance="10"
objecttolerance="10"
gridtolerance="10">
<inkscape:grid
type="xygrid"
id="grid956"
originx="-68.791593"
originy="1.2767161" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
transform="translate(-68.791597,-394.02675)"
style="display:inline">
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 183.34499,416.02062 c -24.661,4.08226 -49.92333,21.30746 -57.18502,32.68484 -8.18178,12.81894 -33.473053,116.65587 -34.496301,163.9888 15.773271,86.16472 55.738681,146.5572 61.556861,154.99421 4.70624,6.82458 9.70825,11.92177 42.30188,12.39158 32.59363,0.46981 37.71496,-5.68647 43.38814,-11.32031 4.79276,-4.75952 54.85052,-92.05678 61.98662,-153.22394 -1.55176,-67.0395 -18.56389,-150.61293 -30.38133,-163.10122 -11.79119,-12.46055 -51.83653,-36.40671 -54.76015,-36.45817 l 0,7.19061 -32.4107,0 z"
id="path870"
sodipodi:nodetypes="cscssscscccc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5040"
d="m 92.50792,592.62443 c 17.91963,82.02052 35.18878,118.28381 72.23883,184.44829"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#bfc2bb;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 216.16981,422.85766 -2.60225,201.6236 c -0.0907,7.03035 -6.07063,10.44123 -13.61129,10.44123 -7.54065,0 -13.50652,-3.41107 -13.61128,-10.44123 l -3,-201.31424 z"
id="rect913"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscc" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="button2"
width="23.15593"
height="57.717773"
x="188.55382"
y="469.01868"
rx="11.577965"
ry="11.577967"
inkscape:label="#rect932" />
<path
sodipodi:nodetypes="cssscc"
inkscape:connector-curvature="0"
id="button5"
d="m 209.20722,547.47605 -0.65676,37.92859 c -0.0779,4.49803 -3.83301,8.12045 -8.59419,8.12045 -4.76117,0 -8.51628,-3.62242 -8.59417,-8.12045 l -0.65677,-37.92859 z"
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path942" />
<path
style="color:#000000;display:inline;overflow:visible;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:10;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="led0"
sodipodi:type="arc"
sodipodi:cx="-729.17651"
sodipodi:cy="199.82953"
sodipodi:rx="13.376111"
sodipodi:ry="13.525835"
sodipodi:start="0.78539816"
sodipodi:end="5.4977871"
sodipodi:arc-type="arc"
d="m -719.71817,209.39374 a 13.376111,13.525835 0 0 1 -18.91668,0 13.376111,13.525835 0 0 1 0,-19.12842 13.376111,13.525835 0 0 1 18.91667,0"
sodipodi:open="true"
transform="matrix(0,-1,1,0,0,0)"
inkscape:label="#path883" />
<path
id="button1"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#bfc2bb;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 298.92308,580.98137 C 293.8094,522.57046 280.3602,462.83778 270.51584,452.43458 258.72465,439.97403 218.67931,416.02787 215.75569,415.97641 l -0.003,7.2085 -0.50645,110.06055 83.95322,47.95787"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscccc"
inkscape:label="#path4278" />
<path
id="button0"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 115.69423,138.97706 -1.12358,-110.662125 -0.0378,-6.147082 C 89.8643,26.095287 64.626024,43.307658 57.368373,54.67871 52.0464,63.017 39.485291,109.86559 31.072821,154.624 c -1.978688,10.52757 -3.72786,20.93951 -5.142655,31.38156 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccsccc"
transform="translate(68.791597,394.02675)"
inkscape:label="#path4256" />
<path
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#bfc2bb;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 299.98341,585.82953 C 288.7813,671.38558 244.14684,741.20584 228.31,776.96473"
id="path5042"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cscssscscccc"
id="path5016"
d="m 183.34499,416.02062 c -24.661,4.08226 -49.92333,21.30746 -57.18502,32.68484 -8.18178,12.81894 -33.47305,116.65587 -34.4963,163.9888 15.77327,86.16472 55.73868,146.5572 61.55686,154.99421 4.70624,6.82458 9.70825,11.92177 42.30188,12.39158 32.59363,0.46981 37.71496,-5.68647 43.38814,-11.32031 4.79276,-4.75952 54.85052,-92.05678 61.98662,-153.22394 -1.55176,-67.0395 -18.56389,-150.61293 -30.38133,-163.10122 -11.79119,-12.46055 -51.83653,-36.40671 -54.76015,-36.45817 l 0,7.19061 -32.4107,0 z"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:connector-curvature="0" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 102.08895,531.68418 c 0.53723,0.0143 -0.15214,3.8319 -0.54934,6.21419 l -7.140506,42.82642 -5.16583,0.42115 8.76037,-44.50491 c 0.466456,-2.3697 1.681005,-5.02125 4.095306,-4.95685 z"
id="button4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssccss"
inkscape:label="#rect921" />
<path
inkscape:label="#path924"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 92.206722,591.3329 c 2.40195,-0.25239 2.836696,1.11858 3.023443,3.52652 l 3.57032,46.03607 c 0.186747,2.40794 -0.771034,3.65494 -3.172974,3.90732 -2.40195,0.25238 -6.087456,-7.10638 -6.124623,-9.52127 l -0.504216,-32.76168 c -0.03717,-2.41488 0.8061,-10.93458 3.20805,-11.18696 z"
id="button3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssss" />
<path
id="led1"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 29.707031,242.95703 c 17.947503,72.58734 50.782189,122.34942 55.957031,129.85352 2.115971,3.06841 4.009169,5.50137 8.642579,7.49023 C 59.190137,317.56953 43.428144,284.03672 27.683594,216.87891 l 2.023437,26.07812 z M 229.75195,201.85742 c -14.69885,84.15847 -52.92757,142.415 -68.74414,178.1543 3.74134,-1.87015 5.74151,-4.04661 8.05469,-6.34375 0.24888,-0.24715 1.70524,-2.23579 3.5293,-5.16992 1.82406,-2.93413 4.19179,-6.95551 6.92187,-11.84375 5.46015,-9.77649 12.37582,-23.01815 19.36133,-38.01368 13.95635,-29.95956 28.17703,-66.96234 31.72656,-97.20898 -0.14948,-6.39067 -0.43956,-12.93267 -0.84961,-19.57422 z"
inkscape:label="#path5630"
inkscape:connector-curvature="0"
transform="translate(68.791597,394.02675)" />
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(-68.791597,5.973336)">
<g
id="button1-path"
inkscape:label="#g131"
transform="translate(8,-8)">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 242.94764,50.505764 234.05236,0"
id="path958"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect968"
width="6.999999"
height="6.999999"
x="237"
y="47.005764" />
<rect
inkscape:label="#rect867"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button1-leader"
width="1"
height="1"
x="477"
y="50.005764" />
</g>
<g
id="button0-path"
inkscape:label="#g141"
transform="translate(8,-8)">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path960"
d="m 477,130.50576 -327.65602,0"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="127.00576"
x="143"
height="6.999999"
width="6.999999"
id="rect970"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect871"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button0-leader"
width="1"
height="1"
x="477"
y="130.00577" />
</g>
<g
id="button4-path"
inkscape:label="#g151"
transform="translate(8,-8)">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path964"
d="M 89.31232,181.51438 117.74787,210.44326 477,210.50576"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect875"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button4-leader"
width="1"
height="1"
x="477"
y="210.00577" />
<rect
y="177"
x="85"
height="6.999999"
width="6.999999"
id="rect974"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
</g>
<g
id="button2-path"
inkscape:label="#g136"
transform="translate(8,-8)">
<rect
inkscape:label="#rect869"
y="90.00576"
x="477"
height="1"
width="1"
id="button2-leader"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 195.97852,108.49147 17.9857,-17.98571 263.03578,0"
id="path908"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect910"
width="6.999999"
height="6.999999"
x="194"
y="104" />
</g>
<g
id="button3-path"
inkscape:label="#g156"
transform="translate(8,-8)">
<path
sodipodi:nodetypes="ccc"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 88.786361,231.47803 18.999029,19.02773 369.21461,0"
id="path966"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect976"
width="6.999999"
height="6.999999"
x="82.883881"
y="225.00577" />
<rect
y="250.00575"
x="477"
height="1"
width="1"
id="button3-leader"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect875" />
</g>
<g
id="button5-path"
inkscape:label="#g146"
transform="translate(8,-8)">
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 476.55132,170.50615 -283.20734,0"
id="path51"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect53"
width="6.999999"
height="6.999999"
x="189"
y="167" />
<rect
y="170"
x="477"
height="1"
width="1"
id="button5-leader"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
style="display:inline"
transform="translate(-68.791597,5.973336)">
<g
id="led0-path"
inkscape:label="#g161"
transform="translate(8,56)">
<path
inkscape:connector-curvature="0"
id="path877"
d="m 477,290.50577 -268.35562,0 -18.97696,-18.97696"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cc" />
<rect
y="269.96875"
x="188.28125"
height="6.999999"
width="6.999999"
id="rect879"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect881"
y="290.00577"
x="477"
height="1"
width="1"
id="led0-leader"
style="color:#000000;text-align:start;display:inline;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="led1-path"
inkscape:label="#g126"
transform="translate(8,274)">
<path
sodipodi:nodetypes="ccc"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 476.99745,10.505764 -192.31824,0 -23.37131,23.307989"
id="path4525"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;text-align:start;display:inline;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="led1-leader"
width="1"
height="1"
x="477"
y="10.005764"
inkscape:label="#rect881" />
<rect
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect4544"
width="6.999999"
height="6.999999"
x="257.69327"
y="30.345425" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="409.2084"
height="411.271"
viewBox="0 0 409.2084 411.27099"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="logitech-g403.svg"
inkscape:export-filename="/home/jimmac/logitech-g403.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142135"
inkscape:cx="223.25242"
inkscape:cy="156.77583"
inkscape:document-units="px"
inkscape:current-layer="LEDs"
inkscape:document-rotation="0"
showgrid="false"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:pagecheckerboard="false"
showguides="true"
inkscape:window-width="1366"
inkscape:window-height="704"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
fit-margin-top="20"
fit-margin-left="20"
fit-margin-bottom="20"
fit-margin-right="0">
<inkscape:grid
type="xygrid"
id="grid956"
originx="-68.791593"
originy="1.2767161" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
transform="translate(-68.791597,-390.00576)">
<path
inkscape:connector-curvature="0"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 175.34499,424.02062 c -24.661,4.08226 -60.18056,22.01925 -69.18502,28.18484 -7.932853,5.43184 -10.801193,13.70196 -10.925233,20.94538 -0.72438,42.30084 10.273313,88.0482 7.561093,130.50252 -1.21026,18.94414 -7.437413,51.01218 -9.969593,64.24176 -1.65073,6.85296 -2.50133,13.87513 -2.53464,20.92508 2.7e-4,50.2338 40.610433,90.95628 90.705683,90.95655 45.46938,-0.0495 82.39643,-34.07041 89.82748,-79.05254 10.66083,-64.53278 10.42629,-136.39723 11.98541,-204.91567 0.28464,-12.50912 -1.94334,-23.29335 -8.32377,-31.80289 -13.26086,-21.57098 -66.73071,-40.02924 -66.73071,-40.02924 v 7.19061 h -32.4107 z"
id="path870"
sodipodi:nodetypes="cssscccssccccc" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 208.56756,431.16702 -3,141.31424 c -0.14923,7.02936 -6.07063,12.69123 -13.61129,12.69123 -7.54065,0 -13.46205,-5.66187 -13.61128,-12.69123 l -3,-141.31424 z"
id="rect913"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscc" />
<path
sodipodi:nodetypes="cscsc"
inkscape:connector-curvature="0"
id="path950"
d="m 95.373251,486.43435 c 38.955159,101.12102 48.667459,140.67087 51.422819,177.84397 2.03646,27.47435 -36.96151,79.62933 -36.96151,79.62933 0,0 -24.033873,-37.15986 -19.463976,-61.45137 10.258966,-54.53208 19.996276,-75.99616 5.002667,-196.02193 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#bfc2bb;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 104.9358,539.80779 c 2.40195,-0.25238 2.7176,0.9048 2.96999,3.30675 l 5.69164,54.1678 c 0.25238,2.40194 -1.47813,4.53882 -3.88008,4.7912 -2.40195,0.25239 -5.44876,-8.75375 -5.55682,-11.1665 l -2.02953,-45.3135 c -0.10806,-2.41275 0.40286,-5.53337 2.8048,-5.78575 z"
id="button4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssss"
inkscape:label="#rect921" />
<path
sodipodi:nodetypes="sssssss"
inkscape:connector-curvature="0"
id="button3"
d="m 109.77779,602.64876 c 2.40195,-0.25239 4.53882,1.47813 4.79121,3.88007 l 5.69164,54.1678 c 0.25238,2.40195 -1.47814,4.53883 -3.88008,4.79121 -2.40195,0.25238 -7.77772,-8.87659 -7.89239,-11.28904 l -1.91843,-40.36308 c -0.11466,-2.41244 0.8061,-10.93458 3.20805,-11.18696 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path924" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="button2"
width="23.155933"
height="69.467796"
x="180.55382"
y="454.99139"
rx="11.577967"
ry="11.577967"
inkscape:label="#rect932" />
<path
sodipodi:nodetypes="cssscc"
inkscape:connector-curvature="0"
id="button5"
d="m 201.20722,551.97605 -0.65676,17.92859 c -0.16469,4.49569 -3.83301,8.12045 -8.59419,8.12045 -4.76117,0 -8.49995,-3.62273 -8.59417,-8.12045 l -0.65677,-17.92859 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path942" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#bfc2bb;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 281.45725,491.14612 c -30.15796,102.59778 -42.11413,137.63368 -50.74442,173.1322 -6.50823,26.76995 22.13723,79.62933 22.13723,79.62933 0,0 13.58979,-21.97214 16.0745,-32.60727 16.80373,-71.92371 12.53269,-220.15426 12.53269,-220.15426 z"
id="path946"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscsc" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#bfc2bb;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 207.75569,423.97641 -1.77476,128.93066 47.96839,25.54626 27.50793,-87.30721 c 4.86457,-36.68335 -44.6715,-55.30429 -73.70156,-67.16971 z"
id="button1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
inkscape:label="#path944" />
<path
sodipodi:nodetypes="ccccsc"
inkscape:connector-curvature="0"
id="button0"
d="m 174.78525,423.6101 3.03798,129.76808 -49.23161,25.07515 -33.218369,-92.01898 c -1.039426,-19.85252 -0.81982,-28.05969 15.888469,-37.87541 17.53477,-10.30125 42.4825,-20.7564 63.52353,-24.94884 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#bfc2bb;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path948" />
<path
style="color:#000000;display:inline;overflow:visible;vector-effect:none;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:10;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="led0"
sodipodi:type="arc"
sodipodi:cx="-656.78052"
sodipodi:cy="189.57951"
sodipodi:rx="19.936752"
sodipodi:ry="19.936752"
sodipodi:start="0.78539816"
sodipodi:end="5.4977871"
sodipodi:arc-type="arc"
d="m -642.6831,203.67693 a 19.936752,19.936752 0 0 1 -28.19483,0 19.936752,19.936752 0 0 1 0,-28.19483 19.936752,19.936752 0 0 1 28.19482,0"
sodipodi:open="true"
transform="rotate(-90)"
inkscape:label="#path883" />
<path
style="fill:#babdb6;fill-opacity:1;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 192.13178,454.61765 c 0,70.18035 0,70.18035 0,70.18035"
id="led1"
inkscape:connector-curvature="0"
inkscape:label="#path42" />
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(-68.791597,9.994236)">
<g
id="button1-path"
inkscape:label="#g131">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 242.94764,50.505764 H 477"
id="path958"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect968"
width="6.999999"
height="6.999999"
x="237"
y="47.005764" />
<rect
inkscape:label="#rect867"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button1-leader"
width="1"
height="1"
x="477"
y="50.005764" />
</g>
<g
id="button0-path"
inkscape:label="#g141">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path960"
d="M 477,130.50576 H 161.34398"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="127.00576"
x="157"
height="6.999999"
width="6.999999"
id="rect970"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect871"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button0-leader"
width="1"
height="1"
x="477"
y="130.00577" />
</g>
<g
id="button4-path"
inkscape:label="#g151">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path964"
d="M 109.31232,181.51438 137.74787,210.44326 477,210.50576"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect875"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button4-leader"
width="1"
height="1"
x="477"
y="210.00577" />
<rect
y="177"
x="105"
height="6.999999"
width="6.999999"
id="rect974"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
</g>
<g
id="button2-path"
inkscape:label="#g136">
<rect
inkscape:label="#rect869"
y="90.00576"
x="477"
height="1"
width="1"
id="button2-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 195.97852,108.49147 17.9857,-17.98571 H 477"
id="path908"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect910"
width="6.999999"
height="6.999999"
x="194"
y="104" />
</g>
<g
id="button3-path"
inkscape:label="#g156">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 114.17805,250.50576 H 477"
id="path966"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect976"
width="6.999999"
height="6.999999"
x="108"
y="247.00577" />
<rect
y="250.00575"
x="477"
height="1"
width="1"
id="button3-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect875" />
</g>
<g
id="button5-path"
inkscape:label="#g146">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 476.55132,170.50615 H 193.34398"
id="path51"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect53"
width="6.999999"
height="6.999999"
x="189"
y="167" />
<rect
y="170"
x="477"
height="1"
width="1"
id="button5-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
style="display:inline"
transform="translate(-68.791597,9.994236)">
<g
id="led0-path"
inkscape:label="#g161">
<path
inkscape:connector-curvature="0"
id="path877"
d="M 477,290.50577 H 208.64438 l -18.97696,-18.97696"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cc" />
<rect
y="271"
x="186"
height="6.999999"
width="6.999999"
id="rect879"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect881"
y="290.00577"
x="477"
height="1"
width="1"
id="led0-leader"
style="color:#000000;text-align:start;display:inline;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="led1-path"
inkscape:label="#g126">
<path
sodipodi:nodetypes="ccc"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 476.99745,10.505764 H 247.7728 l -51.03686,51.503873"
id="path4525"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;text-align:start;display:inline;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="led1-leader"
width="1"
height="1"
x="477"
y="10.005764"
inkscape:label="#rect881" />
<rect
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect4544"
width="6.999999"
height="6.999999"
x="190.67345"
y="59.51358" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,484 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="461.86667"
height="437.33334"
id="svg2"
version="1.1"
inkscape:version="0.92+devel unknown"
sodipodi:docname="logitech-g500.svg"
viewBox="0 0 433 410">
<style
id="style5346" />
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.0000004"
inkscape:cx="184.69456"
inkscape:cy="292.7786"
inkscape:document-units="px"
inkscape:current-layer="Device"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1853"
inkscape:window-height="1016"
inkscape:window-x="1507"
inkscape:window-y="27"
inkscape:window-maximized="1"
units="px"
fit-margin-top="20"
fit-margin-left="-40"
fit-margin-right="-40"
fit-margin-bottom="20"
inkscape:document-rotation="0">
<sodipodi:guide
orientation="-0.98480775,-0.17364818"
position="118.1781,220.98096"
id="guide4656"
inkscape:locked="false" />
<sodipodi:guide
orientation="-0.98480775,-0.17364818"
position="124.47548,146.18232"
id="guide4658"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-115.05694,410.68446"
id="guide5340"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-338.2349,374.49999"
id="guide5342"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-411.98489,294.5"
id="guide5344"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-447.39711,334.5"
id="guide5346"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-458.85989,254.5"
id="guide5348"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-443.23489,214.5"
id="guide5350"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid5352"
empspacing="4"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
originx="0"
originy="0"
spacingx="1"
spacingy="1" />
<sodipodi:guide
orientation="0,1"
position="-305.47013,174.5"
id="guide5354"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Device"
id="Device"
transform="translate(-39.484902,-592.98552)"
style="display:inline"
inkscape:groupmode="layer">
<path
style="fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 256.36569,614.54742 c 62.08413,0.89801 96.39946,43.63605 97.13045,100.21395 0.55781,43.17356 -0.71866,53.46001 -1.54175,67.83715 -2.26656,39.59053 13.49465,51.18855 14.64665,88.65081 1.15816,37.66265 -45.5866,110.51959 -94.81782,110.23536 -65.62864,-0.3789 -122.38269,-97.81594 -122.56938,-158.02971 -0.0782,-25.23502 4.46146,-43.80053 13.87577,-79.40029 -9.23186,-76.55096 33.02958,-130.37871 93.27608,-129.50727 z"
id="path3154"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssssscs" />
<path
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 256.8125,620.48588 c 65.06567,0.698 86.46352,49.92709 87.43313,85.02498 1.40678,50.92328 -31.00828,141.5762 -14.64667,177.30163 8.51955,18.60234 18.50105,43.3618 18.50105,43.3618 0,0 -32.07332,55.55238 -76.12407,55.3104 -47.75882,-0.26237 -83.25468,-52.61233 -83.25468,-52.61233 0,0 18.17404,-39.75596 19.0792,-60.70654 2.21242,-51.20828 -34.1177,-72.31129 -37.00208,-127.19463 -2.92063,-55.57291 17.50781,-121.18975 83.17598,-120.48531 v 47.86067 h -5.96621 c -1.88766,0 -4.0051,2.17484 -4.0051,4.0625 v 39.96094 c 0,1.86907 2.13603,3.98438 4.0051,3.98438 h 5.96621 v 28.98005 h -4.03271 c -0.93786,0 -1.9335,1.10612 -1.9335,2.04398 v 16.95951 c 0,0.93786 0.99564,2.04398 1.9335,2.04398 h 4.03271 v 46.07243 h 2.83814 v -46.07243 h 3.98434 c 0.95705,0 2.01636,-1.08693 2.01636,-2.04398 V 747.3784 c 0,-0.95705 -1.05931,-2.04398 -2.01636,-2.04398 h -3.98434 v -28.98005 h 6.0007 c 1.88748,0 4.0051,-2.0969 4.0051,-3.98438 v -39.96094 c 0,-1.9059 -2.0992,-4.0625 -4.0051,-4.0625 h -6.0007 z"
id="path3156"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscscssccssssccssssccccssssccsssscc" />
<path
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2.13333344;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 228.78906,209.52734 v -24.57031 h -4.30273 c -1.00039,0 -2.0625,-1.18126 -2.0625,-2.18164 v -18.08984 c 0,-1.00039 1.06211,-2.17969 2.0625,-2.17969 h 4.30273 v -30.91211 h -6.36523 c -1.99368,0 -4.27149,-2.25633 -4.27149,-4.25 v -42.625 c 0,-2.013504 2.25798,-4.333984 4.27149,-4.333984 h 6.36523 V 29.333984 C 191.43799,28.933309 167.81063,48.64998 154.36133,76.128906 l 6.78125,13.011719 c 0.88314,1.694805 1.15123,3.956361 0.41211,5.71875 -4.4888,10.703155 -7.116,17.605295 -7.34571,28.384765 -0.037,1.73622 -0.81139,4.42706 -1.86718,4.68164 l -8.53907,1.96094 c -2.34577,34.22551 0.78777,54.03726 19.46485,92.625 l 8.17383,0.56055 c 0.9494,0.0651 1.95013,0.3512 2.86523,0.80273"
transform="matrix(0.93749999,0,0,0.93749999,39.484902,592.98552)"
id="button0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssssccssssccccccccccc" />
<path
sodipodi:nodetypes="ccssssccssssccsc"
inkscape:connector-curvature="0"
id="button1"
d="m 256.8125,789.41811 v -23.03622 h 3.98434 c 0.95705,0 2.01636,-1.08693 2.01636,-2.04398 V 747.3784 c 0,-0.95705 -1.05931,-2.04398 -2.01636,-2.04398 h -3.98434 v -28.98005 h 6.0007 c 1.88748,0 4.0051,-2.0969 4.0051,-3.98438 v -39.96094 c 0,-1.9059 -2.0992,-4.0625 -4.0051,-4.0625 h -6.0007 v -47.86067 c 65.06567,0.698 86.46353,49.92709 87.43313,85.02498 0.70339,25.46164 -7.04868,60.85569 -12.9314,94.35001"
style="fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:label="#path5337" />
<path
style="fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:2.13333344;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 154.36133,76.128906 c -11.77275,24.053464 -15.7471,54.053924 -14.29297,81.722654 2.85731,54.3682 36.47683,77.66427 39.36719,124.46094 l 10.40625,-11.33594 c 1.8935,-2.06288 1.8635,-5.57497 1.24804,-8.30664 -3.12898,-13.88786 -7.08345,-21.76245 -13.9707,-36.16406 -0.95424,-1.99536 -3.47112,-3.28232 -5.67773,-3.43359 l -8.17383,-0.56055 C 144.5905,183.92398 141.45767,164.11281 143.80344,129.8873 l 8.53836,-1.96152 c 1.05579,-0.25458 1.83017,-2.94542 1.86718,-4.68164 0.22971,-10.77947 2.85691,-17.68161 7.34571,-28.384765 0.73912,-1.762389 0.47103,-4.023945 -0.41211,-5.71875 z"
transform="matrix(0.93749999,0,0,0.93749999,39.484902,592.98552)"
id="path4640"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscccccccccccc" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="button2"
width="16"
height="40"
x="247.44788"
y="672.31464"
rx="4"
ry="4"
inkscape:label="#rect4642" />
<rect
style="fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4644"
width="8"
height="15"
x="251.34375"
y="748.26843"
rx="2"
ry="2" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:bevel;stroke-opacity:1"
d="m 184.45535,669.33767 c -2.23196,5.12412 -4.80484,11.95291 -6.46149,18.61989 l 7.35715,1.95705 c 1.0372,-3.57697 2.03018,-5.75654 2.91825,-7.91351 0.52031,-1.26376 0.20456,-3.91971 -0.38116,-5.19416 z"
id="button8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssc"
inkscape:label="#path4646" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:bevel;stroke-opacity:1"
d="m 174.03907,712.2528 c 0.52083,-6.80199 1.39322,-13.37092 2.65623,-18.35938 l 6.99498,1.53292 c -1.25795,4.82258 -1.66687,8.88981 -1.774,12.75056 -0.0294,1.05941 -0.59464,2.39181 -1.62721,2.6306 z"
id="button9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssc"
inkscape:label="#path4648" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 159.55083,740.00544 c -1.24751,0.22588 -2.18342,2.00899 -1.96327,3.25754 l 2.97337,16.86281 4.53764,-0.94696 3.46041,18.3604 1.8943,-0.39559 -6.68317,-37.90213 z"
id="button4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscccccs"
inkscape:label="#path4650" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#bdbab6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 169.00092,779.7656 1.83239,-0.46666 6.87338,38.98084 -4.17452,1.07194 c -1.15216,0.29585 -2.68927,-0.91399 -2.89583,-2.08545 l -3.45729,-19.60726 4.8521,-1.10345 z"
id="button3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccssccc"
inkscape:label="#path4652" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 162.19674,761.50057 6.01776,34.31296 2.99355,-0.71424 -3.77818,-20.44043 -2.54859,-13.7678 z"
id="button5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
inkscape:label="#path4654" />
<path
inkscape:label="#path1148"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.9375;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 238.49468,688.57611 v 7.47706 l -3.59361,-3.59364 z"
id="button6"
inkscape:connector-curvature="0" />
<path
inkscape:label="#path1146"
inkscape:connector-curvature="0"
id="button7"
d="m 272.40108,688.57611 v 7.47706 l 3.5936,-3.59364 z"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.9375;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
</g>
<g
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(-39.484902,-52.623025)"
inkscape:groupmode="layer">
<g
id="button8-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5328"
d="M 183.46993,142.07026 170.4849,128.12301 H 40.484902"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-0"
width="6.999999"
height="6.999999"
x="180.25464"
y="138.46088" />
<rect
inkscape:label="#rect5374"
y="127.62303"
x="39.484901"
height="1"
width="1"
id="button8-leader"
style="text-align:end;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button3-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5338"
d="m 171.875,267.3125 -20.3901,20.81051 H 40.484902"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-4"
width="6.999999"
height="6.999999"
x="168.53668"
y="263.65982" />
<rect
inkscape:label="#rect5376"
transform="translate(39.484902,52.674496)"
y="234.94852"
x="0"
height="1"
width="1"
id="button3-leader"
style="text-align:end;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button5-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5334"
d="m 166.54255,238.69695 -9.05765,9.42606 H 40.484902"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-3"
width="6.999999"
height="6.999999"
x="163.02351"
y="235.40237" />
<rect
inkscape:label="#rect5378"
transform="translate(39.484902,52.674496)"
y="194.94852"
x="0"
height="1"
width="1"
id="button5-leader"
style="text-align:end;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button4-path">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5332"
d="M 161.4849,208.12301 H 40.484902"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-68"
width="6.999999"
height="6.999999"
x="158.37202"
y="204.55347" />
<rect
inkscape:label="#rect5380"
transform="translate(39.484902,52.674496)"
y="154.94852"
x="0"
height="1"
width="1"
id="button4-leader"
style="text-align:end;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button9-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5330"
d="m 178.4278,162.96866 -4.9429,5.15435 H 40.484902"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-99"
width="6.999999"
height="6.999999"
x="175.10759"
y="159.39299" />
<rect
inkscape:label="#rect5382"
transform="translate(39.484902,52.674496)"
y="114.94852"
x="0"
height="1"
width="1"
id="button9-leader"
style="text-align:end;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button6-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5324"
d="m 244.4849,152.62303 95,95.5 132,-2e-5"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-5"
width="6.999999"
height="6.999999"
x="240.37251"
y="148.45215" />
<rect
inkscape:label="#rect5384"
transform="translate(39.484902,52.623025)"
y="195"
x="432"
height="1"
width="1"
id="button6-leader"
style="text-align:start;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button7-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5322"
d="m 267.4849,152.62303 55,55.5 149,-1e-5"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-1"
width="6.999999"
height="6.999999"
x="263.49133"
y="148.45215" />
<rect
inkscape:label="#rect5386"
transform="translate(39.484902,52.623025)"
y="155"
x="432"
height="1"
width="1"
id="button7-leader"
style="text-align:start;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button2-path">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path5326"
d="m 255.4849,141.62303 h 39 l 27,26.5 150,-1e-5"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-6"
width="6.999999"
height="6.999999"
x="251.93195"
y="138.13458" />
<rect
inkscape:label="#rect5388"
transform="translate(39.484902,52.623025)"
y="115"
x="432"
height="1"
width="1"
id="button2-leader"
style="text-align:start;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button1-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5320"
d="m 290.625,110.67188 16.8599,17.45114 h 164"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968-9"
width="6.999999"
height="6.999999"
x="287.23676"
y="107.42233" />
<rect
inkscape:label="#rect5390"
transform="translate(39.484902,52.623025)"
y="75"
x="432"
height="1"
width="1"
id="button1-leader"
style="text-align:start;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
<g
id="button0-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path5318"
d="M 226.27417,106.9604 246.4849,88.123025 h 225"
style="fill:none;stroke:#888a85;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<rect
style="color:#000000;display:inline;overflow:visible;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;marker:none"
id="rect968"
width="6.999999"
height="6.999999"
x="222.83652"
y="103.6103" />
<rect
inkscape:label="#rect5392"
transform="translate(39.484902,52.623025)"
y="35"
x="432"
height="1"
width="1"
id="button0-leader"
style="text-align:start;fill:#888a85;fill-opacity:1;stroke:none" />
</g>
</g>
<g
id="LEDs"
inkscape:label="LEDs"
inkscape:groupmode="layer" />
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1 @@
logitech-g500.svg

View File

@@ -0,0 +1,570 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="467.83105"
height="398.87393"
viewBox="0 0 467.83105 398.87393"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r"
sodipodi:docname="logitech-g502.svg"
inkscape:export-filename="/home/jimmac/logitech-g403.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="345.48859"
inkscape:cy="341.91565"
inkscape:document-units="px"
inkscape:current-layer="Buttons"
inkscape:document-rotation="0"
showgrid="false"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:pagecheckerboard="false"
showguides="true"
inkscape:window-width="1366"
inkscape:window-height="704"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-global="false"
fit-margin-top="20"
fit-margin-bottom="20"
fit-margin-left="0"
fit-margin-right="0">
<inkscape:grid
type="xygrid"
id="grid956"
originx="-16.168953"
originy="-1.1260801" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
transform="translate(-16.168953,-400)"
style="display:inline">
<g
transform="translate(-374,-4.864278e-6)"
id="g1170">
<path
inkscape:connector-curvature="0"
id="path981"
d="m 617.52893,453.41998 -49.99065,26.66899 c -2.22449,1.86937 -2.81832,3.35837 -3.6652,5.83317 l -15.9563,53.34684 c -0.49748,2.25523 -0.34218,3.74811 0.48513,6.46679 l 3.99946,10.9325 -3.53186,0.74244 -1.35901,12.37091 -1.50378,2.8507 2.09912,18.55549 c 0,0 -13.03638,4.81768 -18.22998,15.00854 -5.19361,10.19086 -9.29541,53.53534 -6.03613,59.82001 3.25927,6.28467 25.6018,33.9057 28.70703,40.07849 3.10522,6.17279 24.79553,45.22613 30.93054,51.77106 6.13501,6.54492 35.79895,19.27618 35.79895,19.27618 6.39358,-5.0822 15.98738,-6.80155 23.61682,-0.45557 0,0 31.72192,-10.76812 43.56091,-26.60644 11.83899,-15.83832 24.57691,-52.0235 24.57691,-52.0235 0,0 -2.04663,-1.98694 -2.04663,-9.06775 0,-7.08081 3.24377,-9.90655 3.24377,-9.90655 l -7.41565,-77.33204 c 0,0 0.90478,-68.51501 -1.01514,-76.49939 -1.57946,-6.56849 -5.90589,-29.81348 -7.88675,-38.02183 -0.42699,-1.76936 -0.95122,-1.65743 -2.07882,-3.29921 l -52.65222,-36.341 4.00378,32.1344 h -28.47082 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="ccccccccccsccsccscsccssccccc" />
<path
sodipodi:nodetypes="cccccscssccc"
inkscape:connector-curvature="0"
id="path1014"
d="m 648.06347,618.15601 34.51828,10.05586 c 2.62858,0.8078 3.9256,5.47034 3.9256,5.47034 l -0.44831,35.46611 23.5331,26.29168 c 0,0 -9.4414,38.41029 -27.23181,57.70209 -11.60967,12.58946 -39.46726,23.54443 -39.46726,23.54443 0,0 -4.87562,-48.51623 -9.30469,-56.255 -4.42908,-7.73877 -35.48734,-18.11903 -50.81543,-30.61249 -5.82123,-4.7447 -15.27906,-16.55719 -15.27906,-16.55719 l -4.00329,-23.86047 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#bfc2bb;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
sodipodi:nodetypes="cccsc"
inkscape:connector-curvature="0"
id="path1144"
d="m 620.3461,775.42623 3.91771,-44.34657 c 1.3829,-6.28113 -0.99643,-10.76025 -6.48071,-12.64329 0,0 -33.9759,-17.94313 -41.16454,-25.32697 -7.18863,-7.38383 -16.89702,-24.84664 -16.89702,-24.84664"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
style="color:#000000;display:inline;overflow:visible;vector-effect:none;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:8;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="led1"
sodipodi:type="arc"
sodipodi:cx="-664.05457"
sodipodi:cy="598.10364"
sodipodi:rx="12.162673"
sodipodi:ry="12.162673"
sodipodi:start="0.78539816"
sodipodi:end="5.4977871"
sodipodi:arc-type="arc"
d="m -655.45426,606.70395 a 12.162673,12.162673 0 0 1 -17.20061,0 12.162673,12.162673 0 0 1 0,-17.20062 12.162673,12.162673 0 0 1 17.20061,0"
sodipodi:open="true"
transform="rotate(-90)"
inkscape:label="#path1012" />
<path
sodipodi:nodetypes="ccsccsc"
inkscape:connector-curvature="0"
id="path1030"
d="m 548.10584,591.18781 -1.39021,19.03606 c 0,0 -6.51942,1.07248 -9.54983,9.44719 -3.03041,8.37471 -8.01844,25.6823 -7.19278,55.16199 -3.80454,-3.92381 -8.20043,-7.54825 -7.93855,-14.11229 0.0565,-12.69733 0.50177,-31.56063 5.66468,-49.88965 3.26585,-11.59423 10.35698,-16.87164 20.40669,-19.6433 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
inkscape:connector-curvature="0"
id="button0"
d="m 616.72979,453.87813 -43.21475,23.25557 -2.30905,111.85791 -3.27924,2.29913 8.95587,40.68384 43.49634,-20.81641 c 0,0 -6.29272,-57.3948 -6.04248,-82.96182 0.25025,-25.56702 2.39331,-74.31822 2.39331,-74.31822 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="ccccccsc"
inkscape:label="#path1060" />
<path
inkscape:connector-curvature="0"
id="button1"
d="m 641.35924,447.84438 c 0,0 6.82136,40.56938 7.71833,77.06871 0.89697,36.49932 0.60175,77.20425 0.60175,77.20425 l 43.91543,12.95245 c 0,0 2.9472,-62.03698 1.5412,-81.15454 -1.4061,-19.11755 -6.51723,-50.97735 -8.90483,-54.50845 -2.3876,-3.5311 -44.87188,-31.56242 -44.87188,-31.56242 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cscccsc"
inkscape:label="#path1062" />
<path
inkscape:connector-curvature="0"
id="button8"
d="m 626.36054,592.91458 3.41284,20.82315 12.69293,-3.75027 1.10974,-17.00943 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1064" />
<path
inkscape:connector-curvature="0"
id="path1066"
d="m 624.73297,570.54019 2.51941,13.45651 14.86756,-0.0507 1.26654,-13.4599 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="button2"
width="17.152637"
height="51.954956"
x="623.8761"
y="503.84464"
rx="8.5763187"
ry="8.5763187"
inkscape:label="#rect1068" />
<path
inkscape:connector-curvature="0"
id="button7"
d="m 569.97595,534.59994 -16.73181,-6.63336 13.09595,-44.4487 3.95538,-3.11892 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1098" />
<path
inkscape:connector-curvature="0"
id="button6"
d="m 569.97595,534.59994 -15.81811,4.41446 13.12378,48.26233 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1100" />
<path
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 550.97571,556.55099 -1.73137,22.23376 c 0,0 -8.07466,-0.0385 -6.10341,-6.67814 0.79661,-2.68321 1.88213,-11.10134 3.54027,-13.80998 2.44498,-3.99399 4.29451,-1.74564 4.29451,-1.74564 z"
id="button5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccsc"
inkscape:label="#path1473" />
<path
inkscape:connector-curvature="0"
id="button4"
d="m 553.91685,576.77039 3.78851,43.20785 -3.52893,1.40018 -4.18952,-2.67337 -1.94029,-38.13895 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cccccc"
inkscape:label="#path1118" />
<path
inkscape:connector-curvature="0"
id="button3"
d="m 557.29072,626.42287 -4.13718,-0.69442 -1.90659,6.11048 8.04212,38.1661 3.30713,3.0868 4.6499,-1.78876 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1120" />
<path
inkscape:connector-curvature="0"
id="led0"
d="m 554.07316,558.40614 18.36886,76.63506 -10.78213,5.31523 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1122" />
<path
inkscape:connector-curvature="0"
id="path1138"
d="m 561.0357,599.31803 1.68542,4.21409 -3.19735,5.27031 -0.72068,-4.52978 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
inkscape:connector-curvature="0"
id="path1140"
d="m 564.53845,610.12329 0.75,2.84987 -3.50226,8.03142 -0.75,-4.13156 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
inkscape:connector-curvature="0"
id="path1142"
d="m 566.94537,619.35785 1.45849,3.46056 -4.29748,11.03294 -1.04318,-4.82295 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
inkscape:connector-curvature="0"
id="button9"
d="m 654.80262,526.99557 v 7.97553 l 3.83318,-3.83321 z"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1146" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 608.6358,526.99557 v 7.97553 l -3.83318,-3.83321 z"
id="path1148"
inkscape:connector-curvature="0" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(-16.168953)">
<g
id="button0-path"
inkscape:label="#g442">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path954"
d="m 234.68702,62.49186 41.9857,-41.98571 H 483"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="62"
x="230"
height="6.999999"
width="6.999999"
id="rect952"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect865"
y="20"
x="483"
height="1"
width="1"
id="button0-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="button1-path"
inkscape:label="#g437">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 275.03741,60.50615 H 483.05562"
id="path958"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect968"
width="6.999999"
height="6.999999"
x="273"
y="57" />
<rect
inkscape:label="#rect867"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button1-leader"
width="1"
height="1"
x="483"
y="60" />
</g>
<g
id="button2-path"
inkscape:label="#g432">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path960"
d="M 483.15129,100.50615 H 266.97374 l -7.07445,7.07445"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="106.05299"
x="254.86905"
height="6.999999"
width="6.999999"
id="rect970"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect869"
y="100"
x="483"
height="1"
width="1"
id="button2-leader"
style="color:#000000;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="button6-path"
inkscape:label="#g427">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 483,140.50615 H 189.32589"
id="path962"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect972"
width="6.999999"
height="6.999999"
x="188"
y="137" />
<rect
inkscape:label="#rect871"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button6-leader"
width="1"
height="1"
x="483"
y="140" />
</g>
<g
id="button9-path"
inkscape:label="#g305">
<rect
inkscape:label="button7"
y="-106.99028"
x="-17.168953"
height="1"
width="1"
id="button9-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 17.16895,106.48415 h 196.02823 l 12.07418,12.07418 h 32.523 l 6.63159,11.48624"
id="path902"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect904"
width="6.999999"
height="6.999999"
x="262.93826"
y="128.04514" />
</g>
<g
id="button10-path"
inkscape:label="#g310">
<rect
transform="scale(-1)"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button10-leader"
width="1"
height="1"
x="-17.168953"
y="-146.9903"
inkscape:label="#rect873" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path900"
d="m 17.16895,146.48415 h 136.64539 l 16.12282,-23.87718 h 74.32285 l 4.99222,8.64678"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="128.03354"
x="247.00359"
height="6.999999"
width="6.999999"
id="rect906"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
</g>
<g
id="button4-path"
inkscape:label="#g402">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 17.16895,226.39549 151.60272,0.0884 8.22787,-9.92565"
id="path896"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
y="-219.98177"
x="-181.00188"
height="6.999999"
width="6.999999"
id="rect1297"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
inkscape:label="#rect873"
y="-226.98393"
x="-17.168953"
height="1"
width="1"
id="button4-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
<g
id="button8-path"
inkscape:label="#g397">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path1259"
d="m 17.16895,186.48415 h 90.82321 l 16.12282,16.12282 h 132.34309"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="-207.00615"
x="-262"
height="6.999999"
width="6.999999"
id="rect1261"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
inkscape:label="#rect873"
y="-186.98393"
x="-17.168953"
height="1"
width="1"
id="button8-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
<g
id="button7-path"
inkscape:label="#g300">
<rect
inkscape:label="#rect873"
y="-62.912788"
x="-17.168953"
height="1"
width="1"
id="button7-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path914"
d="M 17.317611,62.412787 H 178.90504 l 15.75447,23.87718"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect912"
width="6.999999"
height="6.999999"
x="191.28058"
y="85.438072" />
</g>
<g
id="button3-path"
inkscape:label="#g407">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path1295"
d="m 17.294405,266.46958 168.568675,0.0407"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
transform="scale(-1)"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect1301"
width="6.999999"
height="6.999999"
x="-191.68813"
y="-269.40173" />
<rect
transform="scale(-1)"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round"
id="button3-leader"
width="1.1351269"
height="1"
x="-17.294409"
y="-266.98993"
inkscape:label="#rect873" />
</g>
<g
id="button5-path"
inkscape:label="#g422">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 483.13134,180.50551 -295.64539,-0.25 -14.35505,-20.22553"
id="path890"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
y="-163.30751"
x="-175.13875"
height="6.999999"
width="6.999999"
id="rect894"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
transform="scale(-1)"
style="color:#000000;text-align:start;display:inline;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button5-leader"
width="1"
height="1"
x="-484.00677"
y="-181.00594"
inkscape:label="#rect873" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
style="display:inline"
transform="translate(-16.168953)">
<g
id="led0-path"
inkscape:label="#g417">
<path
sodipodi:nodetypes="cc"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 191.93858,220.50615 H 483.10224"
id="path966"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect976"
width="6.999999"
height="6.999999"
x="188"
y="217" />
<rect
inkscape:label="#rect875"
style="color:#000000;text-align:start;display:inline;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="led0-leader"
width="1"
height="1"
x="483"
y="220" />
</g>
<g
id="led1-path"
inkscape:label="#g412">
<path
inkscape:connector-curvature="0"
id="path877"
d="M 214.64438,260.50615 H 483"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cc" />
<rect
y="257"
x="210"
height="6.999999"
width="6.999999"
id="rect879"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect881"
y="260"
x="483"
height="1"
width="1"
id="led1-leader"
style="color:#000000;text-align:start;display:inline;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,576 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="467.83105"
height="401.98727"
viewBox="0 0 467.83105 401.98727"
version="1.1"
id="svg8"
inkscape:version="0.92+devel unknown"
sodipodi:docname="logitech-g700.svg"
inkscape:export-filename="/home/jimmac/logitech-g403.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="187.43137"
inkscape:cy="258.73512"
inkscape:document-units="px"
inkscape:current-layer="Device"
inkscape:document-rotation="0"
showgrid="false"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:pagecheckerboard="false"
showguides="true"
inkscape:window-width="1853"
inkscape:window-height="1016"
inkscape:window-x="1507"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:guide-bbox="true"
fit-margin-top="20"
fit-margin-bottom="20"
fit-margin-left="0"
fit-margin-right="0">
<inkscape:grid
type="xygrid"
id="grid956"
originx="-16.168953"
originy="1.9872821" />
<sodipodi:guide
position="566.49402,250.15413"
orientation="0.70710678,0.70710678"
id="guide1516"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="345.16261,205.63403"
orientation="1,0"
id="guide1518"
inkscape:locked="false" />
<sodipodi:guide
position="-91.863214,42.700431"
orientation="-0.70710678,0.70710678"
id="guide1524"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
transform="translate(-16.168953,-400)"
style="display:inline">
<g
id="g372">
<g
transform="translate(-407.70972)"
id="g1433">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 637.21276,442.13269 -7.36914,-7.47852 c 0,0 -28.8291,0.88227 -39.76196,5.88251 -10.93286,5.00025 -25.81714,43.44409 -27.22974,60.10694 -1.41259,16.66284 5.59131,79.27301 5.59131,79.27301 0,0 -24.91552,52.53601 -25.32446,75.27893 -0.76329,42.44959 68.62109,128.5404 134.36865,125.19647 65.74756,-3.34394 84.87379,-61.25208 83.01639,-96.18292 -1.85745,-34.93085 -24.0347,-104.81464 -24.0347,-104.81464 0,0 3.22168,-38.68249 0.51367,-55.62091 -2.708,-16.93842 -11.71606,-56.80554 -18.39038,-64.55786 -6.67431,-7.75232 -37.8457,-17.78882 -37.8457,-17.78882 l -6.53735,7.85638 c -12.1313,-4.07352 -24.5562,-5.43098 -36.99659,-7.15057 z"
id="path1375"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsscssccssccc" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 612.41098,758.14269 c 0,0 26.76334,-11.80523 23.71829,-39.47179 -3.04504,-27.66657 -32.98144,-79.07678 -45.64611,-110.1203 -12.66468,-31.04352 -15.74874,-51.61667 -15.74874,-51.61667 l 23.05147,-8.93851 c 0,0 -7.96118,-20.18219 -6.17273,-34.80102 1.78845,-14.61884 8.3562,-33.93274 8.3562,-33.93274 l -21.43054,-2.36243 c 0,0 5.83261,-22.58934 16.60092,-28.15233 10.76831,-5.56298 19.23914,-5.81466 28.58237,-6.42699 7.5605,-0.4955 15.97198,18.16221 15.97198,18.16221 l 16.26808,2.17394 -0.32704,18.44984 -5.25454,-0.5654 c -3.67431,-0.56751 -4.4221,1.65708 -4.4841,3.99801 l 0.59236,44.46703 c 0.17877,3.31112 2.72713,6.15312 5.36572,6.27812 l 5.67576,0.87203 1.14008,17.91322 -11.71232,-0.0529 c 0,0 0.46941,10.73577 1.62541,15.95522 0.58121,2.62422 2.64643,7.61678 2.64643,7.61678 l -5.41105,14.14438 c -0.3143,4.44983 3.4652,8.4858 6.87092,8.70703 l 5.74669,0.1166 0.0229,11.90123 4.43947,0.27181 0.57583,-12.38929 6.31564,-0.49459 c 3.86404,0 5.05122,-6.48394 4.39517,-9.41658 l -4.08726,-12.49046 c 0,0 2.54921,-4.39682 3.08963,-6.83936 1.19851,-5.41691 0.18619,-16.64269 0.18619,-16.64269 l -10.87259,-0.44848 -0.60938,-17.27195 6.24524,-0.76363 c 4.06456,0.38511 6.77965,-4.10902 6.66305,-6.86494 l -0.33252,-39.01044 c 0.28048,-3.6366 -2.07788,-7.62472 -5.83705,-7.98954 l -8.47677,-0.49546 0.62854,-18.36184 13.79884,0.89971 c 0,0 6.34522,-14.40167 10.99085,-13.74957 4.64563,0.6521 24.41467,6.6986 27.51233,10.86999 3.09765,4.17138 18.99438,49.84112 18.07202,75.55481 -0.92237,25.71368 -9.57337,116.68359 -9.57337,139.14441 0,22.46081 21.64884,69.89563 21.64884,69.89563 -10.48167,14.90232 -31.78702,34.56021 -69.45713,34.56021 -21.63533,0 -42.34124,-8.87714 -61.36398,-22.28231 z"
id="path1382"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssccsccssccccccccccsccccccccccsccccccccccsssscsc" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 142.66406 158.2168 L 130.64258 163.35547 C 130.64258 163.35547 129.76172 163.91431 128.76172 167.41406 C 127.76172 170.91382 137.07617 201.45703 137.07617 201.45703 L 149.06055 210.76562 L 152.07422 210.875 L 152.07227 210.86523 L 149.33594 210.76562 L 144.33008 201.45703 C 144.33008 201.45703 133.88281 169.16187 134.88281 165.66211 C 135.88281 162.16236 137.75195 160.85547 137.75195 160.85547 L 142.72266 158.54492 L 142.66406 158.2168 z "
transform="translate(423.87867,400)"
id="button4" />
<path
inkscape:label="#path1389"
sodipodi:nodetypes="ccccscc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 567.30901,558.21712 8.91914,52.65846 -3.01355,-0.10922 -5.00602,-9.30922 c 0,0 -10.4463,-32.29576 -9.4463,-35.79552 1,-3.49975 2.86811,-4.80649 2.86811,-4.80649 z"
id="button6"
inkscape:connector-curvature="0" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 150.2168 212.87695 C 150.2168 212.87695 142.38943 214.63751 142.22656 219.33398 C 142.06369 224.03045 149.80475 253.7071 153.02734 256.68164 C 156.24994 259.65617 168.61133 259.91016 168.61133 259.91016 L 168.60352 259.88281 C 167.54083 259.83165 160.96579 259.42094 157.99805 256.68164 C 154.77546 253.7071 147.0344 224.03045 147.19727 219.33398 C 147.35939 214.65909 150.57195 212.89894 150.60156 212.88281 L 150.2168 212.87695 z "
transform="translate(423.87867,400)"
id="button3" />
<path
inkscape:label="#path1396"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 578.07507,612.93874 -3.58529,-0.0618 c 0,0 -3.25129,1.76049 -3.41416,6.45696 -0.16287,4.69647 7.57883,34.3726 10.80142,37.34714 3.2226,2.97453 11.00647,3.22825 11.00647,3.22825 z"
id="button5"
inkscape:connector-curvature="0" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 571.80821,529.2887 16.75168,-1.61745 2.26709,2.47905 2.96588,16.7467 -19.4389,7.16674 -3.05292,-21.38677 z"
id="path1398"
inkscape:connector-curvature="0" />
<path
inkscape:label="#path1400"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 572.64727,529.77417 1.93371,12.46355 c 0.17435,1.34405 1.04887,1.97653 2.60016,1.83535 l 12.20529,-1.49705 c 0.75646,-0.10483 2.09687,-1.30513 1.66048,-2.69895 l -1.85475,-11.61027 z"
id="button7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="button2"
width="19.65448"
height="46.726868"
x="650.44757"
y="485.83923"
rx="9.82724"
ry="9.82724"
inkscape:label="#rect932" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 590.00589,504.70809 c 0,0 -1.03484,5.10473 -1.28213,12.10321 -0.16329,4.62125 0.88242,10.235 0.88242,10.235 l -16.1009,0.81035 c -1.3428,0.0627 -2.62237,-0.55688 -2.44997,-2.19533 l -0.0873,-14.82945 1.66055,-5.2578 z"
id="path1408"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscccccc" />
<path
inkscape:label="#path1410"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 573.0899,505.40318 0.20623,15.85869 c -0.0713,1.05397 -0.0531,1.75142 1.13489,1.61532 l 12.98495,-0.46789 c 0,0 -0.15978,-5.93198 0.18903,-8.06114 0.34882,-2.12917 2.24487,-9.58433 2.24487,-9.58433 z"
id="button8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 572.95934,499.38009 c -0.23891,1.10591 0.96351,2.11782 2.59219,2.20621 l 11.93492,0.43018 c 1.44453,-0.125 3.244,-1.82045 3.95047,-4.53981 l 3.64306,-15.04301 c 0.17855,-1.27163 -0.13707,-2.71932 -1.86683,-2.77546 l -13.72539,-1.45781 c -1.4456,-0.0958 -2.68982,1.02632 -2.93832,2.65451 z"
id="path1412"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
inkscape:label="#path1414"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 581.62245,478.87309 c -1.41933,-0.125 -3.23079,0.15096 -3.56732,1.46211 l -2.1321,13.50026 c -0.54179,1.66011 0.55078,2.48769 2.41358,2.75904 l 8.73161,1.00413 c 2.00999,0.16125 2.98232,-1.37377 3.2488,-2.60043 l 3.35525,-12.3699 c 0.31909,-1.42149 0.0372,-2.70382 -1.81709,-2.80852 z"
id="button9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
inkscape:label="#path1416"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 667.01457,578.34297 c 0,0 2.43437,5.37905 2.21672,7.83622 -0.21765,2.45717 0.057,8.12536 0.057,8.12536 -0.084,0.82971 -0.54395,1.59363 -2.16234,1.87243 l -13.39023,-0.0774 c -0.78452,-0.28984 -1.84803,-0.88996 -1.76233,-2.03309 0,0 -0.61952,-8.35025 0.0674,-10.32185 0.68693,-1.97161 1.63297,-5.64161 1.63297,-5.64161 0,0 8.03972,0.11155 13.34081,0.23994 z"
id="button10"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csccccscc" />
<path
inkscape:label="#path1418"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 653.91725,575.19687 13.46749,0.34741 c 0,0 3.20643,-8.97326 3.20643,-11.33956 0,-2.36631 -0.24059,-5.29814 -0.24059,-5.29814 0.14618,-1.05058 -1.20836,-1.93243 -2.12238,-1.98332 h -15.76925 c -1.30503,-0.0224 -1.73401,1.14136 -1.93921,2.31117 0,0 0.0841,7.54347 0.60793,9.21094 0.52379,1.66747 2.78958,6.7515 2.78958,6.7515 z"
id="path1418"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccscccccc" />
<path
sodipodi:nodetypes="ccsccccccccccsssc"
inkscape:connector-curvature="0"
id="button1"
d="m 674.1855,590.4286 -4.08726,-12.49046 c 0,0 2.54921,-4.39682 3.08963,-6.83936 1.19851,-5.41691 0.18619,-16.64269 0.18619,-16.64269 l -10.87259,-0.44848 -0.60938,-17.27195 6.24524,-0.76363 c 4.06456,0.38511 6.77965,-4.10902 6.66305,-6.86494 l -0.33252,-39.01044 c 0.28048,-3.6366 -2.07788,-7.62472 -5.83705,-7.98954 l -8.47677,-0.49546 0.62854,-18.36184 13.79884,0.89971 c 0,0 6.34522,-14.40167 10.99085,-13.74957 4.64563,0.6521 24.41467,6.6986 27.51233,10.86999 3.09765,4.17138 18.99439,49.84112 18.07202,75.55481 -0.46118,12.85684 -2.85453,42.02774 -5.13257,70.79203"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 590.48316,608.5506 c -12.66468,-31.04352 -15.74874,-51.61667 -15.74874,-51.61667 l 23.05147,-8.93851 c 0,0 -7.96118,-20.18219 -6.17273,-34.80102 1.78845,-14.61884 8.3562,-33.93274 8.3562,-33.93274 l -21.43054,-2.36243 c 0,0 5.83261,-22.58934 16.60092,-28.15233 10.76831,-5.56298 19.23914,-5.81466 28.58237,-6.42699 7.5605,-0.4955 15.97198,18.16221 15.97198,18.16221 l 16.26808,2.17394 -0.32704,18.44984 -5.25454,-0.5654 c -3.67431,-0.56751 -4.4221,1.65708 -4.4841,3.99801 l 0.59236,44.46703 c 0.17877,3.31112 2.72713,6.15312 5.36572,6.27812 l 5.67576,0.87203 1.14008,17.91322 -11.71232,-0.0529 c 0,0 0.46941,10.73577 1.62541,15.95522 0.58121,2.62422 2.64643,7.61678 2.64643,7.61678 l -5.41105,14.14438"
id="button0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccsccssccccccccccscc" />
</g>
<path
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 274.29495,505.2149 v 7.97553 l 3.83318,-3.83321 z"
id="button12"
inkscape:connector-curvature="0"
inkscape:label="#path1146" />
<path
inkscape:connector-curvature="0"
id="button11"
d="m 230.83554,505.2149 v 7.97553 l -3.83318,-3.83321 z"
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path1148" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(-16.168953)">
<g
id="button0-path"
inkscape:label="#g226">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path954"
d="m 234.68702,62.49186 41.9857,-41.98571 H 483"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="62"
x="230"
height="6.999999"
width="6.999999"
id="rect952"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect865"
y="20"
x="483"
height="1"
width="1"
id="button0-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="button1-path"
inkscape:label="#g221">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 275.03741,60.50615 H 483.05562"
id="path958"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect968"
width="6.999999"
height="6.999999"
x="273"
y="57" />
<rect
inkscape:label="#rect867"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button1-leader"
width="1"
height="1"
x="483"
y="60" />
</g>
<g
id="button9-path"
inkscape:label="#g216">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path960"
d="M 483,100.50615 H 361.43709 L 336.37251,75.396706 H 189.62772 l -8.6513,10"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="82.008446"
x="177.07306"
height="6.999999"
width="6.999999"
id="rect970"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect869"
y="100"
x="483"
height="1"
width="1"
id="button9-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="button12-path"
inkscape:label="#g206">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path964"
d="M 483.5,180.00615 H 360.68314 l -59.54024,-65.8551 -33.2008,0.0451"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="109.90022"
x="264.5123"
height="6.999999"
width="6.999999"
id="rect974"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect873"
y="179.50615"
x="483"
height="1"
width="1"
id="button12-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
<g
id="button7-path"
inkscape:label="#g171">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="M 17.151054,140.50027 H 182.33834"
id="path76"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect972"
width="6.999999"
height="6.999999"
x="176.04955"
y="136.99055" />
<rect
transform="scale(-1)"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button7-leader"
width="1"
height="1"
x="-17.168953"
y="-141.00027"
inkscape:label="#rect873" />
</g>
<g
id="button10-path"
inkscape:label="#g176">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path1259"
d="M 17.16895,180.50027 H 246.82196"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="-184.26186"
x="-252.73283"
height="6.999999"
width="6.999999"
id="rect1261"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
inkscape:label="#rect873"
y="-181.00027"
x="-17.168953"
height="1"
width="1"
id="button10-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
<g
id="button6-path"
inkscape:label="#g181">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path1295"
d="m 17.16895,220.50027 h 33.151095 l 30.12282,-29.87718 h 81.709115"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="-194.0271"
x="-167.2599"
height="6.999999"
width="6.999999"
id="rect1297"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
transform="scale(-1)"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button6-leader"
width="1"
height="1"
x="-17.168953"
y="-221.00027"
inkscape:label="#rect873" />
</g>
<g
id="button4-path"
inkscape:label="#g186">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 17.16895,260.50027 h 42.566708 l 60.284632,-61.94843 h 31.82975"
id="path1299"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<rect
transform="scale(-1)"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect1301"
width="6.999999"
height="6.999999"
x="-156.24265"
y="-202.01924" />
<rect
inkscape:label="#rect873"
y="-261.00027"
x="-17.168953"
height="1"
width="1"
id="button4-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
<g
id="button11-path"
inkscape:label="#g211">
<rect
inkscape:label="#rect871"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button11-leader"
width="1"
height="1"
x="483"
y="140" />
<path
inkscape:connector-curvature="0"
id="path1512"
d="M 482.98501,140.50615 H 359.31376 l -34.84984,-39.6734 -82.25306,-0.004"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="cccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect1514"
width="6.999999"
height="6.999999"
x="235.83218"
y="99.10099" />
</g>
<g
id="button3-path"
inkscape:label="#g191">
<path
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 17.16895,300.50027 h 51.327469 l 81.344411,-79.98695 h 10.85261"
id="path1502"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<rect
transform="scale(-1)"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect1504"
width="6.999999"
height="6.999999"
x="-164.00285"
y="-223.98463" />
<rect
transform="scale(-1)"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button3-leader"
width="1"
height="1"
x="-17.168953"
y="-301.00027"
inkscape:label="#rect873" />
</g>
<g
id="button5-path"
inkscape:label="#g196">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path1506"
d="M 17.16895,340.50027 H 97.369601 L 183.06798,252.94705"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="-253.98224"
x="-185.04956"
height="6.999999"
width="6.999999"
id="rect1508"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1)" />
<rect
inkscape:label="#rect873"
y="-341.00027"
x="-17.168953"
height="1"
width="1"
id="button5-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
<g
id="button2-path"
inkscape:label="#g201">
<path
sodipodi:nodetypes="ccc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 482.7753,220.37357 -139.89827,-0.0147 -91.18642,-98.70563"
id="path962"
inkscape:connector-curvature="0" />
<rect
y="219.87363"
x="483"
height="1"
width="1"
id="button2-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
<rect
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect436"
width="6.999999"
height="6.999999"
x="246.30431"
y="116.44096" />
</g>
<g
id="button8-path"
inkscape:label="#g166">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path438"
d="m 17.282046,100.50073 138.615124,0.125 20.88991,20.36764"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="116.02772"
x="174.8121"
height="6.999999"
width="6.999999"
id="rect1435"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect873"
y="-101.00027"
x="-17.168953"
height="1"
width="1"
id="button8-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
style="display:inline"
transform="translate(-16.168953)" />
</svg>

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,516 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="482.65375"
height="409.75723"
viewBox="0 0 482.65374 409.75722"
version="1.1"
id="svg8"
inkscape:version="0.91 r13725"
sodipodi:docname="roccat-kone-xtd.svg"
inkscape:export-filename="/home/jimmac/logitech-g403.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<inkscape:path-effect
effect="spiro"
id="path-effect4426"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4416"
is_visible="true" />
<inkscape:path-effect
is_visible="true"
id="path-effect4412"
effect="spiro" />
<inkscape:path-effect
effect="spiro"
id="path-effect4397"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4384"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4380"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4368"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4360"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4193"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect4185"
is_visible="true" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="-64.59026"
inkscape:cy="199.95686"
inkscape:document-units="px"
inkscape:current-layer="Buttons"
inkscape:document-rotation="0"
showgrid="false"
units="px"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:pagecheckerboard="false"
showguides="true"
inkscape:window-width="1920"
inkscape:window-height="1101"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1"
fit-margin-top="20"
fit-margin-left="0"
fit-margin-bottom="20"
fit-margin-right="0"
inkscape:guide-bbox="true"
guidetolerance="10"
objecttolerance="10"
gridtolerance="10">
<inkscape:grid
type="xygrid"
id="grid956"
originx="36.653759"
originy="3.4686305" />
<sodipodi:guide
position="125.24434,292.81279"
orientation="1,0"
id="guide4350" />
<sodipodi:guide
position="232.01745,389.68642"
orientation="0,1"
id="guide4352" />
<sodipodi:guide
position="339.49769,179.67571"
orientation="1,0"
id="guide4354" />
<sodipodi:guide
position="262.42305,21.283798"
orientation="0,1"
id="guide4356" />
<sodipodi:guide
position="61.51829,157.33126"
orientation="1,0"
id="guide5867" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
transform="translate(36.653757,-393.71139)"
style="display:inline">
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 122.82453,740.37034 c -19.02281,-23.41625 -31.616134,-52.28805 -34.233943,-82.34359 -2.096443,-24.06963 2.128869,-48.32241 8.95101,-71.5 2.158331,-7.33273 4.577033,-14.58882 7.250003,-21.75 -1.3982,-18.81093 -1.06298,-37.75033 1,-56.5 2.52814,-22.97724 7.65448,-45.66761 15.25,-67.5 l 13.25,-11.25 141.5,-5.25 c 12.02953,26.7963 18.37607,56.12763 18.5,85.5 0.12121,28.72967 -5.62197,57.27681 -5,86 0.24638,11.37797 1.49774,22.75148 4.0739,33.8367 3.20755,13.80209 8.47842,27.26326 9.22845,41.4133 0.66161,12.48182 -2.27756,24.99565 -7.36927,36.41091 -5.0917,11.41525 -12.28663,21.79231 -20.30154,31.38369 -9.49466,11.36219 -20.28557,21.78699 -32.84623,29.62777 -12.56066,7.84078 -26.98545,13.02513 -41.78531,13.48575 -15.18013,0.47246 -30.29151,-4.05272 -43.44909,-11.63807 -13.15758,-7.58536 -24.44174,-18.13853 -34.01798,-29.92646 z"
id="path4382"
inkscape:path-effect="#path-effect4384"
inkscape:original-d="m 122.82453,740.37034 c 0,0 -34.233943,-46.59359 -34.233943,-82.34359 0,-35.75 5.95101,-62.75 8.95101,-71.5 3.000003,-8.75 7.250003,-21.75 7.250003,-21.75 25.62768,0 -0.25,-44 1,-56.5 1.25,-12.5 15.25,-67.5 15.25,-67.5 l 13.25,-11.25 141.5,-5.25 c 0,0 18.25,53.25 18.5,85.5 0.25,32.25 -5.25,74.75 -5,86 0.125,5.625 0.81574,20.14113 4.0739,33.8367 3.25816,13.69557 6.83375,29.07057 9.22845,41.4133 0.84882,4.375 -22.22676,62.14156 -27.67081,67.7946 -24.05895,24.98254 -60.00654,43.19257 -74.63154,43.11352 -48.05458,-0.25976 -77.46707,-41.56453 -77.46707,-41.56453 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscscccssssssc" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 134.2916,429.52675 -12.75,12.5 c -12.31411,36.57641 -16.0253,76.01857 -10.75,114.25 6.1427,44.5177 24.24594,87.57778 23,132.5 -0.49267,17.76334 -4.06145,35.43727 -10.5,52 8.39201,13.20649 20.3144,24.14654 34.19206,31.37481 13.87766,7.22828 29.67603,10.72678 45.30794,10.03331 29.20955,-1.29581 57.30887,-17.926 72.5,-42.90812 -6.99047,-28.36406 -8.86284,-57.98142 -5.5,-87 5.139,-44.34544 22.31262,-86.91141 24.5,-131.5 1.63092,-33.24546 -5.32115,-66.87607 -20,-96.75 l -14,-9.49452 c -20.53616,-0.82089 -41.13517,-0.0647 -61.55586,2.25985 -21.78053,2.4793 -43.35766,6.74311 -64.44414,12.73467 z"
id="path4378"
inkscape:original-d="m 134.2916,429.52675 -12.75,12.5 c 0,0 -18.75,71.75 -10.75,114.25 8,42.5 23.42774,101.24777 23,132.5 -0.42774,31.25223 -10.5,52 -10.5,52 0,0 43.5,41.40812 79.5,41.40812 36,0 72.5,-42.90812 72.5,-42.90812 0,0 -20,-25.5 -5.5,-87 14.5,-61.5 23,-104.5 24.5,-131.5 1.5,-27 -20,-96.75 -20,-96.75 l -14,-9.49452 c -22.40781,-0.31655 -36.15781,-0.75 -61.55586,2.25985 -25.99748,3.08089 -64.44414,12.73467 -64.44414,12.73467 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccszcscssccsc"
inkscape:path-effect="#path-effect4380" />
<path
style="fill:none;fill-rule:evenodd;stroke:#babdb6;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 102.95061,567.96501 c 0.70002,22.44793 2.65772,43.37669 3.30638,62.88708 0.52948,15.92576 7.34749,40.38934 -4.69813,38.78754 -4.929835,-0.65556 -12.883112,-9.26574 -13.017313,-24.73788"
id="path4401"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssc" />
<path
inkscape:label="#path924"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 104.14503,591.78576 c 2.70152,2.04148 8.34731,2.78189 8.46463,3.52635 l 7.53906,47.84087 c 0.37596,2.38573 -1.6214,1.86287 -1.6214,1.86287 -2.38894,0.35504 -11.76758,-6.66231 -11.90814,-9.07339 l -1.90715,-32.71 c -0.14062,-2.41107 -0.567,-11.4467 -0.567,-11.4467 z"
id="button4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscssc" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 105.59036,538.91245 c 0.52253,-0.12564 0.84775,3.74005 1.08254,6.14378 l 4.20424,41.21202 -6.91297,-2.23542 -3.04198,-39.25359 c -0.1866,-2.40794 2.31991,-5.30229 4.66817,-5.86679 z"
id="button3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssccss"
inkscape:label="#rect921" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 216.66981,463.35766 c 7.7882,31.51628 -3.10225,161.1236 -3.10225,161.1236 -0.13535,7.02963 -6.07063,10.44123 -13.61129,10.44123 -7.54065,0 -13.50233,-3.41113 -13.61128,-10.44123 0,0 -10.54298,-129.82998 -2.5,-161.31424 8.04298,-31.48426 11.005,-29.3064 16.58919,-29.26346 5.58419,0.0429 8.44743,-2.06218 16.23563,29.4541 z"
id="rect913"
inkscape:connector-curvature="0"
sodipodi:nodetypes="zssszzz" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="button2"
width="23.15593"
height="57.717773"
x="188.55382"
y="461.01868"
rx="11.577965"
ry="11.577967"
inkscape:label="#rect932" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="button9"
d="m 209.20722,524.3296 -0.65676,27.92859 -17.18836,0 -0.65677,-27.92859 z"
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path942" />
<path
inkscape:label="#path942"
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 208.41172,565.23341 -1.86126,32.17123 c -0.25984,4.4912 -1.83301,4.12045 -6.59419,4.12045 -4.76117,0 -6.33658,0.37088 -6.59417,-4.12045 l -1.94966,-31.99445 z"
id="button10"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssscc" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 199.58066,416.69667 c -0.28142,0.0314 -0.56434,0.0637 -0.8457,0.0957 -21.78053,2.47931 -43.35688,6.74282 -64.44336,12.73438 l -5.24219,5.13867 c -4.63188,14.23762 -6.48452,22.56972 -10.85742,51.73047 -2.31322,15.42571 0.0333,42.97083 4.37695,70.53516 20.18393,0.10496 59.33211,-0.93056 59.53906,0.375 l 0.0371,-0.30274 c -1.67671,-36.75209 -2.37374,-77.8923 1.69922,-93.83594 6.49241,-25.41455 9.67504,-28.8908 13.59766,-29.26562 l 2.25586,-0.10352 z"
id="button0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccscccsccc" />
<path
inkscape:label="#path942"
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 208.55097,552.1948 -5e-4,13.20984 -17.18836,0 -5.2e-4,-13.17859 z"
id="path4391"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="button11"
d="m 206.55097,441.9448 1.9995,15.20984 -17.18836,0 1.99948,-15.17859 z"
style="color:#000000;overflow:visible;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path942" />
<path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 245.09433,414.2123 c -15.20199,-0.0324 -30.40556,0.79698 -45.51367,2.48437 l 0.33399,17.16016 1.96093,0.0351 c 4.68444,-0.0473 7.71457,0.81299 14.79493,29.46485 3.87599,15.68486 3.12444,55.66092 1.39257,91.86914 l 0.23829,1.79297 60.07421,0.69336 c 8.82289,-52.62093 4.27435,-90.98774 -13.62695,-139.62696 l -0.13281,-0.62109 -4.32422,-2.93164 c -5.0633,-0.2024 -10.12994,-0.30953 -15.19727,-0.32031 z"
id="button1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccscccccccc" />
<path
id="led0"
style="fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 290.24244,554.46605 c -5.26976,49.56099 -36.23031,99.47705 -15.28225,184.71113 -3.16837,4.44852 -3.173,4.56365 -8.05566,10.86971 -17.84401,-50.57656 -7.8566,-125.64401 4.04428,-156.62518 17.6011,-72.50699 15.50543,-116.35777 -6.20089,-175.33551 l 9.29158,5.5835 c 10.82003,25.11299 27.5667,64.49596 16.20294,130.79635 z m -180.19239,-2.47487 c 7.61079,68.82965 34.53563,125.64 13.2841,188.42344 3.24708,3.97977 8.53092,12.44446 12.34811,15.28913 18.99515,-41.57656 13.57812,-98.28741 2.86138,-129.26858 -11.32886,-31.75516 -24.92286,-109.55879 -20.35212,-140.03876 4.57073,-30.47997 6.3548,-38.13399 11.4734,-53.63774 l -10.11812,10.8868 c -9.96888,31.30753 -13.36232,66.4405 -9.49675,108.34571 z"
inkscape:label="#path5753"
inkscape:connector-curvature="0" />
<path
inkscape:label="#path1146"
inkscape:connector-curvature="0"
id="button6"
d="m 221.59975,489.94486 0,7.97552 3.83318,-3.83321 z"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<path
inkscape:label="#path1148"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 178.14034,489.94486 0,7.97552 -3.83318,-3.83321 z"
id="button5"
inkscape:connector-curvature="0" />
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
style="display:inline"
transform="translate(36.653757,6.2887068)">
<g
id="button1-path"
inkscape:label="#g131"
transform="translate(8,72)">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 242.94764,50.505764 194.05236,0"
id="path958"
inkscape:connector-curvature="0" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect968"
width="6.999999"
height="6.999999"
x="237"
y="47.005764" />
<rect
inkscape:label="#rect867"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button1-leader"
width="1"
height="1"
x="437"
y="50.005764" />
</g>
<g
id="button11-path"
inkscape:label="#g141"
transform="translate(8,-88)">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path960"
d="m 437,130.50576 -237.65602,0 -3.89602,3.89602"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path960" />
<rect
y="133.00577"
x="189"
height="6.999999"
width="6.999999"
id="rect970"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#rect970" />
<rect
inkscape:label="#rect871"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button11-leader"
width="1"
height="1"
x="437"
y="130.00577" />
</g>
<g
id="button2-path"
inkscape:label="#g136"
transform="translate(8,-8)">
<rect
inkscape:label="#rect869"
y="90.00576"
x="437"
height="1"
width="1"
id="button2-leader"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 195.97852,94.49147 3.9857,-3.98571 237.03578,0"
id="path908"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect910"
width="6.999999"
height="6.999999"
x="190"
y="92" />
</g>
<g
id="button10-path"
inkscape:label="#g146"
transform="translate(8,-8)">
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 436.55132,170.50615 -223.20734,0 -18.11371,18.15319"
id="path51"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect53"
width="6.999999"
height="6.999999"
x="189"
y="187" />
<rect
y="170"
x="437"
height="1"
width="1"
id="button10-leader"
style="color:#000000;text-align:start;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
<g
transform="translate(-72.0872,-77.953227)"
style="display:inline"
id="button9-path"
inkscape:label="#g191">
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 37.16895,300.50027 59.327469,0 79.344411,-79.98695 96.85261,0"
id="path1502"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<rect
transform="scale(-1,-1)"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect1504"
width="6.999999"
height="6.999999"
x="-276.00287"
y="-223.98463" />
<rect
transform="scale(-1,-1)"
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button9-leader"
width="1"
height="1"
x="-37.168953"
y="-301.00027"
inkscape:label="#rect873" />
</g>
<g
transform="translate(-72.82271,-38.03545)"
style="display:inline"
id="button4-path"
inkscape:label="#g196">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path1506"
d="m 37.16895,340.50027 60.200651,0 87.698379,-87.55322"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
y="-257.98224"
x="-187.04956"
height="6.999999"
width="6.999999"
id="rect1508"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1,-1)" />
<rect
inkscape:label="#rect873"
y="-341.00027"
x="-37.168953"
height="1"
width="1"
id="button4-leader"
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1,-1)" />
</g>
<g
inkscape:label="#g196"
id="button3-path"
style="display:inline"
transform="translate(-72.82271,-78.03545)">
<path
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 37.16895,340.50027 60.200651,0 83.698379,-83.55322"
id="path5817"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<rect
transform="scale(-1,-1)"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="rect5819"
width="6.999999"
height="6.999999"
x="-183.04956"
y="-261.98224" />
<rect
transform="scale(-1,-1)"
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button3-leader"
width="1"
height="1"
x="-37.168953"
y="-341.00027"
inkscape:label="#rect873" />
</g>
<g
inkscape:label="#g191"
id="button0-path"
style="display:inline"
transform="translate(-72.0872,-137.95323)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="button0-line"
d="m 37.16895,320.50027 59.327469,0 99.344411,-99.98695 26.85261,0"
style="color:#000000;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
inkscape:label="#path5841" />
<rect
y="-223.98463"
x="-226.00287"
height="6.999999"
width="6.999999"
id="button0-rect"
style="color:#000000;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
transform="scale(-1,-1)"
inkscape:label="#rect5843" />
<rect
inkscape:label="#rect873"
y="-321.00027"
x="-37.168953"
height="1"
width="1"
id="button0-leader"
style="color:#000000;text-align:end;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
transform="scale(-1,-1)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
style="display:inline"
transform="translate(36.653757,6.2887068)">
<g
id="led0-path"
inkscape:label="#g161"
transform="translate(8,56)">
<path
inkscape:connector-curvature="0"
id="path877"
d="m 437,290.50577 -158.35562,0 -18.97696,-18.97696"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
sodipodi:nodetypes="ccc" />
<rect
y="269.96875"
x="256.28125"
height="6.999999"
width="6.999999"
id="rect879"
style="color:#000000;display:inline;overflow:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
<rect
inkscape:label="#rect881"
y="290.00577"
x="437"
height="1"
width="1"
id="led0-leader"
style="color:#000000;text-align:start;display:inline;overflow:visible;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,578 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 198.4375 198.43751"
version="1.1"
id="svg124"
inkscape:version="0.92.1 r"
sodipodi:docname="g303_FINAL.svg">
<defs
id="defs118">
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker10743"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path10741" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker8938"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path8936"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker8458"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"
inkscape:collect="always">
<path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path8456" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker7654"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path7652"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker7210"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Mend"
inkscape:collect="always">
<path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path7208" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mend"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path5595"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path5589"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path5571"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5568"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4831"
x1="85.155098"
y1="123.48504"
x2="71.876953"
y2="109.32611"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient4680-3">
<stop
style="stop-color:#212121;stop-opacity:1"
offset="0"
id="stop4676" />
<stop
style="stop-color:#525252;stop-opacity:1"
offset="1"
id="stop4678" />
</linearGradient>
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4837"
gradientUnits="userSpaceOnUse"
x1="75.392632"
y1="113.90072"
x2="78.325882"
y2="111.17885" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4820"
gradientUnits="userSpaceOnUse"
x1="58.802368"
y1="98.166107"
x2="67.821754"
y2="105.06921" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4812"
x1="65.554306"
y1="101.39091"
x2="57.845005"
y2="94.387032"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4801"
gradientUnits="userSpaceOnUse"
x1="93.544136"
y1="74.89328"
x2="97.026817"
y2="75.489372" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4796"
x1="100.40672"
y1="76.753265"
x2="102.15361"
y2="76.166771"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4682"
x1="78.691124"
y1="106.60219"
x2="134.32263"
y2="145.19518"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4705"
x1="63.324043"
y1="92.412109"
x2="52.236984"
y2="73.76532"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.797201)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="radialGradient4695"
cx="112.96842"
cy="113.917"
fx="112.96842"
fy="113.917"
r="41.164257"
gradientTransform="matrix(1.2281683,0,0,1.296401,-19.641241,-30.306952)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4710"
gradientUnits="userSpaceOnUse"
x1="41.81852"
y1="81.23703"
x2="81.993874"
y2="81.23703"
gradientTransform="matrix(1.2281683,0,0,1.2458588,-20.199812,-21.716256)" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4763"
x1="67.125862"
y1="69.888031"
x2="82.802811"
y2="69.888031"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4773"
x1="77.743431"
y1="69.896729"
x2="74.04789"
y2="65.264908"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4747"
x1="80.881615"
y1="74.891853"
x2="82.567528"
y2="70.608902"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4784"
x1="89.6782"
y1="82.01104"
x2="124.02607"
y2="82.01104"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4735"
gradientUnits="userSpaceOnUse"
x1="81.290771"
y1="69.214806"
x2="58.49073"
y2="60.248428" />
<linearGradient
gradientTransform="matrix(1.2281683,0,0,1.2458588,-19.641241,-24.549337)"
inkscape:collect="always"
xlink:href="#linearGradient4680-3"
id="linearGradient4726"
x1="58.34309"
y1="66.386375"
x2="116.9311"
y2="66.386375"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.92824696"
inkscape:cx="267.03408"
inkscape:cy="338.19237"
inkscape:document-units="mm"
inkscape:current-layer="layer7"
showgrid="false"
units="px"
inkscape:snap-page="true"
inkscape:snap-others="false"
inkscape:window-width="1920"
inkscape:window-height="1004"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1" />
<metadata
id="metadata121">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer7"
inkscape:label="Device"
style="display:inline">
<path
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 33.641311,64.982766 -1.732765,5.398727 c 0,0 -0.629464,5.678443 3.26926,11.20272 5.812872,8.815493 5.94101,9.101914 13.151365,19.243577 7.210355,10.14167 20.613506,27.64865 32.12776,42.84454 3.87757,5.11741 16.967127,10.29767 21.949299,12.68881 11.002,5.28032 27.527,13.09076 40.11549,14.1146 15.07422,1.22601 22.74792,-23.13102 22.74792,-23.13102 L 141.75352,83.564426 123.90176,65.732277 102.89006,58.202973 62.293831,52.176488 45.213712,60.714006 Z"
id="path4839"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccczsssccccccc" />
<path
sodipodi:nodetypes="cccssccsc"
inkscape:connector-curvature="0"
id="path4728"
d="m 54.76863,55.588789 -2.295328,-2.726405 -0.27808,-2.350686 c 0,0 18.167671,-1.598465 22.431514,-0.940273 4.263843,0.658192 23.729205,5.171504 34.852264,9.590788 11.12306,4.419288 9.18583,4.11904 14.42276,6.57006 -8.85487,-3.133919 -23.66007,-1.760792 -33.812723,-1.477175 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.76863,55.588789 54.76863,55.588789 Z"
style="display:inline;fill:url(#linearGradient4726);fill-opacity:1;stroke:none;stroke-width:0.32780018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="display:inline;fill:url(#linearGradient4735);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 54.856148,55.855125 -2.382846,-2.992741 -0.27808,-2.350686 c 18.481975,6.870889 20.73837,7.57628 37.893815,13.7434 -0.158622,1.548423 -0.114268,2.600247 -0.114268,2.600247 C 82.7929,64.986082 54.856148,55.855125 54.856148,55.855125 Z"
id="path4716"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccsc" />
<path
style="display:inline;fill:url(#linearGradient4784);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 90.498682,64.587538 c 0.0014,2.415136 0.08886,3.214144 0.08886,3.214144 l 37.938998,22.41657 4.1571,0.443891 -3.58823,-15.047953 -32.119065,-9.854412 z"
id="path4776"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient4747);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 48.926779,56.570799 c 0,0 5.569607,-2.071605 6.497874,-2.13438 4.641336,1.255515 31.870514,10.044141 37.068811,12.052968 9.897016,3.978673 20.493146,9.162891 28.404966,13.999022 5.31807,3.262227 8.52923,5.401083 8.10688,7.972533 -0.42234,2.571452 -4.45568,5.900935 -4.45568,5.900935 0,0 -13.11951,-3.389899 -13.49083,-3.641 -0.37131,-0.251104 -18.627219,-14.438453 -18.627219,-14.438453 0,0 -13.119512,-5.335949 -13.552706,-5.587054 C 78.445686,70.444268 64.831094,63.978353 64.521671,63.915577 64.212247,63.852802 48.926779,56.570799 48.926779,56.570799 Z"
id="path4739"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccczcccccc" />
<path
inkscape:connector-curvature="0"
id="path4765"
d="m 62.800615,61.187683 c 0.06391,-0.129654 1.75539,-2.692898 4.595099,-4.082141 1.130065,-0.55285 4.463428,-1.655606 6.038322,-1.200179 4.493777,1.299505 7.905733,3.09382 12.483497,10.149265 -3.2066,1.658274 -3.2066,1.658274 -3.2066,1.658274 l -2.49426,0.310726 z"
style="display:inline;fill:url(#linearGradient4773);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="csscccc" />
<path
style="display:inline;fill:url(#linearGradient4763);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 62.800615,61.187683 c 0.08752,-0.177557 3.063124,-5.903769 8.708027,-3.639918 5.644906,2.263853 10.545906,10.120748 10.545906,10.120748 l -1.837875,0.355115 z"
id="path4755"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="csscssscc"
inkscape:connector-curvature="0"
id="path4707"
d="m 81.061034,68.55619 c 0,0 -6.675185,12.538586 -10.603076,22.010152 -1.049126,2.529831 -2.28668,5.867231 -2.803926,7.547057 -0.660926,2.146451 -0.08433,2.769521 -0.397665,4.358811 -3.844082,-2.632003 -32.505527,-27.735224 -34.22755,-29.787815 -0.242782,-0.289387 -1.233891,-1.962381 -1.42236,-4.307299 -0.05219,-0.649308 -0.04284,-1.350134 0.06099,-2.087368 0.836918,-5.94284 11.1851,-12.607804 11.1851,-12.607804 z"
style="display:inline;fill:url(#linearGradient4710);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cscssccsscsscscc"
inkscape:connector-curvature="0"
id="path4670"
d="m 82.41522,69.014086 c 0,0 23.31399,10.073283 38.80002,21.370661 1.81334,1.322871 4.49209,1.676486 6.63621,-0.04062 2.14412,-1.717108 1.62492,-3.937097 -0.92121,-6.104499 -4.95885,-4.221241 -6.85739,-5.122344 -13.18638,-8.905281 -7.90195,-4.723139 -16.853771,-8.967037 -23.245174,-10.746814 9.140702,-0.572366 30.023744,-1.337857 33.403074,1.144738 8.87412,3.960851 24.30645,16.663516 31.24281,27.830947 8.63308,13.899132 12.33164,22.248122 14.23506,36.388812 2.80518,20.83995 -16.13732,43.5 -26.85791,40.5237 3.57946,-0.6342 7.33514,-2.175 6.9966,-5.15132 -0.74082,-6.51284 -8.57647,-16.59867 -48.52475,-38.11975 -18.315639,-9.86707 -32.387452,-23.46711 -32.387452,-23.46711 0,0 -0.214496,-1.83679 0.169271,-3.37698 C 71.534502,89.287367 82.41522,69.014083 82.41522,69.014083 Z"
style="display:inline;fill:url(#radialGradient4695);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="display:inline;fill:url(#linearGradient4705);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 67.336162,99.153458 -0.07979,3.237812 C 63.412286,99.759262 35.095451,75.716531 33.028818,72.77516 c -1.88514,-2.683054 -1.67797,-6.628929 -0.815272,-8.362198 -0.06626,1.61221 -0.485638,3.84076 1.152105,5.623249 7.675602,8.353979 25.95005,21.003692 33.970511,29.117247 z"
id="path178"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccscsc" />
<path
style="display:inline;fill:url(#linearGradient4682);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 142.52172,170.47574 c 3.57946,-0.6342 7.33514,-2.17499 6.9966,-5.15132 -0.74082,-6.51285 -8.57647,-16.59867 -48.52476,-38.11975 -18.315635,-9.86707 -32.387446,-23.46711 -32.387446,-23.46711 0,0 -0.214498,-1.8368 0.169271,-3.37698 3.725669,4.47916 22.509918,18.21415 41.851065,29.0174 55.62333,31.06912 43.85529,42.27142 31.89527,41.09776 z"
id="path4672"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssccsc" />
<path
style="display:inline;fill:url(#linearGradient4796);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 91.506481,71.019901 c 0.743609,0.908331 11.844809,6.076214 14.221649,7.257645 0.71803,0.356899 1.1815,0.799004 2.31924,0.621448 1.13772,-0.177558 2.35863,-1.316437 2.47237,-1.642404 0.12819,-0.367406 -2.52196,-5.346011 -2.73493,-5.570848 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -1.679248,0.660653 -2.406747,1.242898 -0.758403,0.606982 -2.320732,1.856577 -1.969149,2.286046 z"
id="path4788"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscsssss" />
<path
sodipodi:nodetypes="csssc"
inkscape:connector-curvature="0"
id="path4798"
d="m 105.24679,73.239364 c 0.34525,0.02969 2.75099,-1.328785 2.53802,-1.553622 -0.15339,-0.161933 -11.5427,-4.126769 -11.902433,-4.194785 -0.229293,-0.04336 -2.23807,0.99583 -2.472384,1.487039 -0.208466,0.437022 10.535617,4.077407 11.836797,4.261368 z"
style="display:inline;fill:url(#linearGradient4801);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="display:inline;fill:url(#linearGradient4812);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 48.060396,93.734116 16.089967,15.317314 1.980305,-0.87885 1.732766,-3.76656 -17.080119,-14.81511 -1.856536,1.129967 z"
id="path4804"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4814"
d="m 48.060396,93.734116 16.089967,15.317314 1.608998,-3.8921 C 61.694393,101.39187 50.213564,91.368976 48.926779,90.720877 Z"
style="display:inline;fill:url(#linearGradient4820);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="cccscssc"
inkscape:connector-curvature="0"
id="path4833"
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 7.5516,-4.23009 10.658617,-6.2986 0.393265,-0.26182 1.06751,-0.26234 -0.417721,-1.26676 -1.485226,-1.0044 -15.684249,-10.57631 -21.967626,-16.10646 -0.272557,-0.23987 -2.024894,0.70814 -2.197279,1.00972 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
style="display:inline;fill:url(#linearGradient4837);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="display:inline;fill:url(#linearGradient4831);fill-opacity:1;stroke:none;stroke-width:0.32728478px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 68.002673,113.587 c 2.885039,3.27285 9.816521,11.87315 14.171552,17.07503 0.376971,0.45027 0.479604,0.86316 1.593523,0.36097 1.113922,-0.50223 5.494927,-2.76524 8.601948,-4.83374 0.393264,-0.26183 1.067506,-0.70624 -0.417724,-1.71067 -1.485226,-1.0044 -14.896587,-10.13241 -21.179966,-15.66256 -0.272558,-0.23988 -0.755882,-0.75671 -0.928267,-0.45513 -0.968716,1.69477 -1.430234,3.61135 -1.841066,5.2261 z"
id="path4823"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccscssc" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Leaders"
style="display:inline">
<path
style="fill:none;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 87.372004,82.225427 c 0,0 19.527816,7.279613 31.390236,17.304521 0,0 3.8591,1.194482 5.60489,-0.183766 1.74578,-1.378252 1.19448,-3.032155 -0.64318,-4.686055 -1.83767,-1.6539 -20.39812,-13.414976 -29.770225,-15.987711 7.442555,-0.459415 24.445965,-1.073843 27.197485,0.918834 7.22549,3.179214 19.79081,13.375125 25.43853,22.33877 7.02923,11.15626 10.04068,17.85767 11.59048,29.20782 2.28404,16.72738 -13.13933,34.91569 -21.86825,32.52672 2.91447,-0.50904 5.97242,-1.74578 5.69677,-4.13475 -0.60319,-5.2276 -6.98314,-13.32309 -39.50986,-30.59717 -14.912972,-7.91989 -26.370532,-18.8361 -26.370532,-18.8361 0,0 -0.174647,-1.47432 0.137824,-2.71056 2.246527,-8.888015 11.105832,-25.160553 11.105832,-25.160553 z"
id="path4668"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csccccsscsscsc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="14.064545"
y="42.284489"
id="text4889"><tspan
sodipodi:role="line"
id="tspan4887"
x="14.064545"
y="42.284489"
style="font-size:4.23333311px;stroke-width:0.26458332">Button 0</tspan></text>
<text
id="text4977"
y="41.314796"
x="99.894806"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="41.314796"
x="99.894806"
sodipodi:role="line"
id="tspan4979">Button 2</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="55.512764"
y="30.319952"
id="text4985"><tspan
sodipodi:role="line"
x="55.512764"
y="30.319952"
style="stroke-width:0.26458332"
id="tspan4987">Button 1</tspan></text>
<text
id="text4993"
y="122.63442"
x="20.689524"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="122.63442"
x="20.689524"
sodipodi:role="line"
id="tspan4995">Button 4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="55.262302"
y="153.98589"
id="text5001"><tspan
sodipodi:role="line"
x="55.262302"
y="153.98589"
style="stroke-width:0.26458332"
id="tspan5003">Button 3</tspan></text>
<text
id="text5009"
y="63.37672"
x="141.62805"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="63.37672"
x="141.62805"
sodipodi:role="line"
id="tspan5011">Button 5</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
d="M 65.843199,148.27125 72.399014,138.295"
id="path5023"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path7206"
d="m 41.615182,120.90785 13.396667,-6.27079"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7210)" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7654)"
d="m 22.80284,45.37344 11.401419,9.121127"
id="path7650"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path8454"
d="m 66.128235,34.542092 4.275532,11.686446"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8458)" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8938)"
d="M 98.052209,43.663228 82.660292,57.629958"
id="path8934"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path10739"
d="m 140.23745,65.040889 -28.50355,5.13063"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10743)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,778 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="logitech-g502.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4372">
<stop
style="stop-color:#3d444c;stop-opacity:1"
offset="0"
id="stop4374" />
<stop
style="stop-color:#8f9aaa;stop-opacity:1"
offset="1"
id="stop4376" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4327">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4329" />
<stop
style="stop-color:#969696;stop-opacity:1"
offset="1"
id="stop4331" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4319">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4321" />
<stop
style="stop-color:#969696;stop-opacity:1"
offset="1"
id="stop4323" />
</linearGradient>
<linearGradient
id="linearGradient4219">
<stop
style="stop-color:#c3c3c3;stop-opacity:1;"
offset="0"
id="stop4221" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4223" />
</linearGradient>
<linearGradient
id="linearGradient4197">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4199" />
<stop
id="stop4205"
offset="0.23127364"
style="stop-color:#242424;stop-opacity:1;" />
<stop
style="stop-color:#242424;stop-opacity:1;"
offset="0.7880435"
id="stop4207" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop4201" />
</linearGradient>
<linearGradient
id="linearGradient4178">
<stop
id="stop4180"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.46853611"
id="stop4182" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.84132797"
id="stop4184" />
<stop
id="stop4186"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4168">
<stop
id="stop4170"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.646918"
id="stop4172" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.76408035"
id="stop4174" />
<stop
id="stop4176"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4150">
<stop
id="stop4152"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.54100561"
id="stop4154" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.84132797"
id="stop4156" />
<stop
id="stop4158"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4140">
<stop
id="stop4142"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
style="stop-color:#3b3b3b;stop-opacity:1;"
offset="0.5890528"
id="stop4144" />
<stop
style="stop-color:#777777;stop-opacity:1;"
offset="0.69403088"
id="stop4146" />
<stop
id="stop4148"
offset="1"
style="stop-color:#000000;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient4047">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4049" />
<stop
id="stop4055"
offset="0.5"
style="stop-color:#000000;stop-opacity:0.49803922;" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4051" />
</linearGradient>
<linearGradient
id="linearGradient4039">
<stop
style="stop-color:#636363;stop-opacity:1;"
offset="0"
id="stop4041" />
<stop
id="stop4063"
offset="0.19902708"
style="stop-color:#595959;stop-opacity:1;" />
<stop
id="stop4061"
offset="0.39056408"
style="stop-color:#4f4f4f;stop-opacity:1;" />
<stop
style="stop-color:#a3a3a3;stop-opacity:1;"
offset="1"
id="stop4043" />
</linearGradient>
<linearGradient
id="linearGradient4449">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4451" />
<stop
id="stop4059"
offset="0.24691147"
style="stop-color:#3b3b3b;stop-opacity:1;" />
<stop
id="stop4057"
offset="0.84132797"
style="stop-color:#777777;stop-opacity:1;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4453" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4562"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.698701,1.698701,0,-120.19569,737.44997)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4449"
id="linearGradient4623"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.6987012,-1.6987012,0,-45.565631,793.48827)"
x1="31.968746"
y1="18.546629"
x2="31.968746"
y2="29.577879" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4319"
id="linearGradient4325"
x1="-258.85849"
y1="636.73883"
x2="-210.58292"
y2="669.61383"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4327"
id="linearGradient4333"
x1="-258.85849"
y1="636.73883"
x2="-210.58292"
y2="669.61383"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4372"
id="linearGradient4378"
x1="476.00003"
y1="513.00006"
x2="559.50006"
y2="463.50003"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="359.25033"
inkscape:cy="331.87231"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
showguides="false"
inkscape:guide-bbox="true"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="2048"
inkscape:window-height="1088"
inkscape:window-x="2560"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,-165.96284)"
style="display:inline"
sodipodi:insensitive="true">
<g
id="g4390"
transform="translate(46.66905,-6.3639614)">
<path
sodipodi:nodetypes="zccccccscsscssssssssz"
inkscape:connector-curvature="0"
id="path4435"
d="m -226.16095,683.58782 c -6.01535,-13.02364 -13,-16.5 -13,-16.5 l -11.25,-3.375 -116.45795,-88.57547 11.4905,-82.02437 7.62132,1.97703 6.89061,-13.15685 c -18.38478,2.65165 -27.23986,-1.01777 -28.47729,-2.60876 -1.23744,-1.59099 0.17677,-3.18198 0.17677,-3.18198 0,0 7.43505,-10.39747 47.55294,-23.33452 117.72759,-37.96429 194.75285,-32.63933 310.328127,14.65494 101.699787,41.61632 127.995243,117.50993 130.641353,159.47011 0,0 -2.38649,0.17677 -5.74524,5.03813 -3.35876,4.86136 6.0104,17.05896 3.53553,28.72622 -2.47487,11.66726 -28.637827,53.29817 -45.166448,48.70198 -16.528622,-4.5962 -39.067651,-6.98268 -55.154331,-3.00521 -16.08667977,3.97748 -95.017477,43.75224 -100.144001,46.66905 -5.126525,2.91682 -19.26866,10.42983 -25.36746,10.87177 -6.09879,0.44194 -18.29639,-4.06586 -45.25483,-14.05375 -26.95845,-9.98788 -54.09367,-22.98097 -61.25313,-32.88046 -7.15946,-9.8995 -4.95112,-20.38922 -10.96647,-33.41286 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4362"
transform="translate(-522.78594,165.96281)"
d="m 564.2793,394.82812 c -3.92575,-0.10626 -7.28936,3.75042 -13.08985,11.8711 -8.83883,12.37437 -39.24401,61.16451 -77.07422,75.30664 -37.83021,14.14214 -97.93406,2.12147 -130.10742,-1.41406 -32.07532,-3.52476 -80.61133,-16.61719 -80.61133,-16.61719 l -30.16601,4.00391 39.14453,29.77148 11.25,3.375 c 0,0 6.98465,3.47636 13,16.5 6.01535,13.02364 3.80734,23.51261 10.9668,33.41211 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 6.0988,-0.44194 20.24066,-7.95623 25.36719,-10.87305 5.12652,-2.91681 84.05785,-42.69049 100.14453,-46.66797 16.08668,-3.97747 38.62567,-1.59229 55.15429,3.00391 16.52863,4.59619 42.69115,-37.03392 45.16602,-48.70117 0.81145,-3.82542 0.34164,-7.70307 -0.52734,-11.36524 -4.70923,-11.20032 -11.76875,-25.18057 -21.7461,-38.13281 -23.82425,-30.92783 -38.18467,-40.65753 -46.3164,-47.02149 -2.79529,-2.18761 -5.00616,-3.33105 -7.0625,-3.38672 z"
style="fill:url(#linearGradient4378);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4356">
<path
inkscape:connector-curvature="0"
style="fill:#2e2d2b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 130.91406,379.34375 c -0.46995,0.14042 -0.93877,0.27563 -1.41015,0.42187 0,10e-6 -1.6703,5.53928 -1.51758,6.25196 l 51.97265,21.91992 23.86524,-17.50195 2.72461,-3.55664 c -0.22885,-0.14243 -0.45999,-0.27609 -0.68945,-0.41602 -27.39877,-3.31358 -52.27682,-5.25289 -75.04493,-6.2793 l 0.0996,-0.83984 z"
transform="translate(-522.78594,165.96281)"
id="path4417" />
<path
inkscape:connector-curvature="0"
style="fill:#13130f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 128.01367,386.0293 4.48633,9.0957 66,39.375 -18.53906,-26.56445 -0.002,0.002 -51.94531,-21.9082 z"
transform="translate(-522.78594,165.96281)"
id="path4422" />
<path
inkscape:connector-curvature="0"
style="fill:#7c7a79;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 203.82422,390.61328 c 0,0 -0.57509,0.25215 -0.60156,0.26367 l -23.26172,17.0586 18.38281,26.33984 -1.14844,-4.50586 0.79492,-17.32422 5.83399,-21.83203 z"
transform="translate(-522.78594,165.96281)"
id="path4427" />
</g>
<path
inkscape:connector-curvature="0"
id="path4216"
transform="translate(-522.78594,165.96281)"
d="M 411.19922,269.32812 C 389.02158,276.55183 382.23256,283.7763 371.75,291 l 25.375,6.25 c 18.2282,-19.41084 23.88453,-20.47312 31.20117,-23.95898 -5.76229,-1.45746 -11.46778,-2.78139 -17.12695,-3.9629 z"
style="fill:#3d4144;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4220"
d="m -170.91095,464.08782 -8.5,16.125 35.75,3.25 1.625,-16.25 z"
style="fill:#3c4247;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cssccccc"
inkscape:connector-curvature="0"
id="path4226"
transform="translate(-522.78594,165.96281)"
d="m 411.17969,269.33398 c -24.50302,-5.11518 -48.18402,-7.65405 -72.22657,-7.57031 -42.56105,0.14824 -86.27544,8.47266 -137.78124,25.08203 -40.11789,12.93705 -47.55274,23.33399 -47.55274,23.33399 0,0 -0.48629,0.56241 -0.63476,1.3457 l 0.10351,0.0684 c 65.05383,-30.40559 116.42376,-36.77027 218.33008,-20.63869 11.09267,-7.17661 17.60011,-14.39959 39.76172,-21.62112 z"
style="fill:#363c41;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4263"
transform="translate(-522.78594,165.96281)"
d="m 296.87305,518.20312 c 5.68645,12.75421 3.66653,23.08278 10.71875,32.83399 7.15946,9.89949 34.2935,22.89298 61.25195,32.88086 26.95844,9.98789 39.15707,14.49663 45.25586,14.05469 5.82656,-0.42222 18.90685,-7.25764 24.54101,-10.41407 -0.55038,-0.0177 -1.10725,-0.03 -1.64062,-0.0586 -7,-0.375 -17.75,-3.625 -26.375,-6.5 -8.625,-2.875 -67.14947,-20.67049 -76.375,-33.125 -7.10507,-9.59187 -5.33684,-16.54135 -8.83008,-19.27148 -2.49111,-1.94692 -8.34261,-3.73063 -12.5039,-5.15625 -3.08671,-1.05747 -11.18273,-3.67568 -16.04297,-5.24415 z"
style="fill:#10f5fa;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4348">
<path
inkscape:connector-curvature="0"
style="fill:#a6a09b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 244.0293,281.64062 c -11.87933,0.21005 -21.28719,4.70945 -25.45899,14.41407 l -7.76367,15.2207 c 4.63005,-8.00151 13.38623,-11.7657 24.20703,-11.95703 13.84985,-0.24489 31.05521,5.35529 47.24414,15.31641 4.24517,-2.44738 6.87171,-7.03619 7.65625,-8.34375 0.83684,-1.39473 3.09281,-4.54246 4.70703,-7.20118 -17.13681,-11.29215 -35.78244,-17.71107 -50.59179,-17.44922 z m -33.22266,29.63477 c -0.45292,0.78273 -0.88022,1.59229 -1.25195,2.45703 l 1.25195,-2.45703 z"
transform="translate(-522.78594,165.96281)"
id="path4228" />
<path
style="fill:#0c0d08;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 210.77539,311.25976 -1.12305,2.28126 c -0.45554,2.37144 2.75076,4.2831 5.21875,3.9746 2.82843,-0.35354 20.06602,-2.56346 32.97071,-2.74023 12.9047,-0.17678 22.09591,1.76761 29.34375,1.41406 1.88682,-0.092 3.57816,-0.69332 5.07226,-1.55468 -16.18893,-9.96112 -33.39429,-15.5613 -47.24414,-15.31641 -10.8208,0.19133 -19.60823,3.93989 -24.23828,11.9414 z"
id="path4247"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssscsc"
transform="translate(-522.78594,165.96281)" />
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4258"
d="m -179.35432,480.17165 -2.95971,5.51668 39.24443,5.56847 -0.88388,-7.86656 z"
style="fill:#111419;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4260"
d="m -143.07496,491.2041 -1.00352,-7.90761 2.03293,-16.10721 1.45082,6.56663 z"
style="fill:#282d32;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
id="g4352">
<path
style="fill:#2f333a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -313.91094,553.83781 -2.375,3.5 -3.875,14.125 93.375,-1.625 c -21.95804,-4.72268 -46.10785,-9.6343 -87.125,-16 z"
id="path4262"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="cccccc"
style="fill:#585958;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -320.16094,571.44718 -3.125,23.01563 3.25,7.125 99.5,-15.375 -6.29687,-16.40625 z"
id="path4264"
inkscape:connector-curvature="0" />
</g>
<g
id="g4335">
<path
style="fill:url(#linearGradient4333);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4325);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -295.16094,608.46281 6.625,27.125 27.125,5.875 c 0,0 38.75,14.5 45.75,29.125 l 5.5,0.875 2.375,-4.625 c 0,0 -13.875,-23.75 -49.625,-33.375 l -1,-1.25 2.25,-11.25 z"
id="path4288"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<path
style="fill:#1f2021;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 235.18359,469.82617 272.125,497.75 l 35,6.875 C 300.125,490 261.375,475.5 261.375,475.5 Z"
transform="translate(-522.78594,165.96281)"
id="path4290"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
</g>
<g
id="g4297">
<path
style="fill:#5e5d5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -271.28594,618.46281 4,7 85.38128,13.44194 9.61872,-8.44194 z"
id="path4266"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#242422;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -181.07659,638.77695 c 0,0 22.18548,12.55115 -5.48008,8.04334 -27.66555,-4.5078 -67.97064,-12.55114 -67.97064,-12.55114 l -12.72792,-8.75045 z"
id="path4268"
inkscape:connector-curvature="0" />
<path
style="fill:#5e6570;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -172.41453,630.38006 -9.45755,8.3085 9.28077,8.3969 9.54594,-5.3033 z"
id="path4270"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -271.48416,618.56636 2.19822,-8.60355 103.25,9.875 6,18.125 -2.625,3.875 -9.60983,-10.91789 z"
id="path4280"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
<g
id="g4305">
<path
style="fill:#676763;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -164.98991,632.50138 6.18718,9.72272 75.041708,8.22011 8.131734,-6.54073 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
id="path4272"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:#2f343b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -70.32599,631.08717 5.48008,5.39169 -5.74524,12.90469 -5.204655,-5.54257 c 0.08832,-4.98178 3.353501,-8.62593 5.469815,-12.75381 z"
id="path4274"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#202328;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -83.58424,650.17905 3.8007,4.06586 -77.87014,-6.89429 -1.15104,-5.14215 z"
id="path4276"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4278"
d="m -70.59115,649.38355 -9.1397,4.91406 -3.894905,-4.1034 7.819685,-6.37912 z"
style="fill:#97a6b5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4292"
d="m -153.03036,495.18342 44.96255,6.76837 1.76776,125.51145 -32.51219,-3.18198 z"
style="fill:#676769;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#181719;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -164.98991,632.50138 89.360622,11.4021 1.155328,-4.55469 4.153795,-8.23574 -93.255535,-9.12988 z"
id="path4303"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<g
id="g4282">
<path
style="fill:#9b9994;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -283.96063,605.18939 1.59099,4.06586 144.42656,16.26346 -6.01041,-45.07806 z"
id="path4244"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 312.64258,435.04297 -5.01172,0.64453 8.00195,8.8418 5.88281,0.41015 -8.87304,-9.89648 z"
transform="translate(-522.78594,165.96281)"
id="path4246" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 331.68945,432.58984 -4.78515,0.61524 11.86718,12.93945 6.72461,0.4707 -13.80664,-14.02539 z"
transform="translate(-522.78594,165.96281)"
id="path4248" />
<path
inkscape:connector-curvature="0"
style="fill:#2cbfff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 351.97266,429.97852 -6.13282,0.78906 16.58594,17.0293 7.58399,0.52929 -18.03711,-18.34765 z"
transform="translate(-522.78594,165.96281)"
id="path4250" />
</g>
<g
id="g4339">
<path
style="fill:#4c5053;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -386.31433,498.06271 -5.65686,48.08326 c 45.99186,2.07336 100.55399,7.85718 167.23075,21.21321 l 1.06066,3.0052 c 23.24045,-1.15617 46.44002,-2.32824 77.95852,-0.26516 l 3.35876,3.62392 -10.6066,-78.48885 c -119.63944,-15.8417 -179.55343,-5.16228 -233.34523,2.82842 z"
id="path3608"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
inkscape:connector-curvature="0"
style="fill:#413d44;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 344.67578,403.00977 c -16.50546,-0.0586 -30.99426,0.6673 -45.49414,1.38867 l 6.64258,15.02929 74.77539,-10.96093 -0.94727,-1.53907 -2.58789,-2.79101 c -11.81943,-0.77366 -22.46808,-1.09174 -32.38867,-1.12695 z"
transform="translate(-522.78594,165.96281)"
id="path4412" />
<path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -296.22345,497.71282 4.375,6.6875 6.875,-6.8125 z"
id="path4242"
inkscape:connector-curvature="0" />
</g>
<g
style="stroke:none"
id="g4344">
<path
style="fill:#6d747e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 428.32422,273.29297 c -7.29616,3.47575 -12.94858,4.55152 -31.06055,23.8125 0.0479,0.0864 0.0803,0.17102 0.13086,0.25781 6.62912,19.7106 10.60547,165.375 10.60547,165.375 0,0 41.19295,7.2655 67.125,1.38672 22.33947,-5.06434 38.625,-29.625 51.125,-42.625 12.5,-13 24.89365,-35.29164 33.5,-37.875 6.89763,-2.07046 15.8234,4.4109 29.125,12.375 33.4418,20.02269 42.89394,39.55603 52.79297,65.09375 0.30214,-0.10531 0.47265,-0.12305 0.47265,-0.12305 C 639.49453,419.01054 613.19977,343.11632 511.5,301.5 481.65769,289.2883 454.39027,279.88532 428.32422,273.29297 Z"
transform="translate(-522.78594,165.96281)"
id="path4234"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccssssccsc" />
<ellipse
style="opacity:1;fill:#2cbfff;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4261"
cx="-58.535938"
cy="561.08783"
rx="32.25"
ry="29.875" />
</g>
<path
inkscape:connector-curvature="0"
id="path4218"
d="m -205.53595,454.96282 -11.375,19 21.5,-0.875 10.875,-18.875 z"
style="fill:#202124;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4254"
d="m -222.88428,483.39024 6.01577,-9.47808 21.47301,-0.86336 1.23744,11.49049 z"
style="fill:#121518;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4256"
d="m -195.50442,473.05324 10.88157,-18.79455 2.39721,10.39322 -12.00029,19.91863 z"
style="fill:#1a1e22;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<path
inkscape:connector-curvature="0"
id="path4556"
d="m -94.323676,683.09816 5.56391,3.21163 5.56059,3.21159 0,-3.66282 11.76151,0 -1.59253,-2.7604 1.59253,-2.76039 -11.76151,0 0,-3.66282 -5.56059,3.21162 -5.56391,3.21159 z"
style="display:inline;fill:url(#linearGradient4562);fill-opacity:1;stroke:none" />
<path
inkscape:connector-curvature="0"
id="use4558"
d="m -71.437651,739.13645 -5.56391,3.21162 -5.56059,3.21159 0,-3.66282 -11.76152,0 1.59254,-2.76039 -1.59254,-2.76039 11.76152,0 0,-3.66282 5.56059,3.21161 5.56391,3.2116 z"
style="fill:url(#linearGradient4623);fill-opacity:1;stroke:none" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-507.44232"
y="412.75952"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="-507.44232"
y="412.75952"
style="font-size:32px">Button0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-60.689339"
y="696.94501"
id="text4505"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4507"
x="-60.689339"
y="696.94501"
style="font-size:32px">Button10</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4509"
y="753.67065"
x="-60.689339"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="753.67065"
x="-60.689339"
id="tspan4511"
sodipodi:role="line"
style="font-size:32px">Button9</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4440"
y="467.91382"
x="-507.44232"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="467.91382"
x="-507.44232"
id="tspan4442"
sodipodi:role="line">Button7</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4448"
d="m -501.44135,408.77695 79.19595,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -290.72353,319.68149 38.18376,-118.08684"
id="path4450"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
sodipodi:linespacing="125%"
id="text4452"
y="209.51634"
x="-419.71732"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:Sans;-inkscape-font-specification:Sans"
y="209.51634"
x="-419.71732"
id="tspan4454"
sodipodi:role="line">Button2</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4456"
d="M -355.77735,340.18759 -422.9525,219.97943"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path4466"
d="m -302.74434,651.31459 94.0452,-113.8442"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-507.44232"
y="516.70416"
id="text4468"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4470"
x="-507.44232"
y="516.70416"
style="font-size:32px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4472"
y="566.90875"
x="-455.11642"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="566.90875"
x="-455.11642"
id="tspan4474"
sodipodi:role="line">Button4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-456.53064"
y="616.40625"
id="text4476"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4478"
x="-456.53064"
y="616.40625"
style="font-size:32px">Button5</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4480"
y="662.36816"
x="-310.86664"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="662.36816"
x="-310.86664"
id="tspan4482"
sodipodi:role="line">Button3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40.00000381px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:left;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;display:inline;fill:#000000;fill-opacity:1;stroke:none"
x="-252.13301"
y="200.32396"
id="text4484"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4486"
x="-252.13301"
y="200.32396"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:Sans;-inkscape-font-specification:Sans">Button1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4488"
y="247.93217"
x="-103.82285"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:32px"
y="247.93217"
x="-103.82285"
id="tspan4490"
sodipodi:role="line">Button8</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -502.14846,464.63839 60.10407,-12.72792"
id="path4492"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4494"
d="m -496.4916,512.72165 126.57211,-43.84061"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -445.57991,562.92624 140.71425,-43.84062"
id="path4496"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4498"
d="m -439.21595,608.88818 100.40916,-61.51829"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M -232.03365,357.15816 -108.28996,250.38503"
id="path4500"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -1,352 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="logitech-mx_master.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient5204">
<stop
style="stop-color:#868686;stop-opacity:1;"
offset="0"
id="stop5206" />
<stop
style="stop-color:#868686;stop-opacity:0;"
offset="1"
id="stop5208" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient5128">
<stop
style="stop-color:#3a3a3a;stop-opacity:1"
offset="0"
id="stop5130" />
<stop
style="stop-color:#aaaaaa;stop-opacity:1"
offset="1"
id="stop5132" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5128"
id="linearGradient3078"
gradientUnits="userSpaceOnUse"
spreadMethod="reflect"
x1="230.63638"
y1="432.30179"
x2="238.061"
y2="447.85815" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5204"
id="linearGradient3080"
gradientUnits="userSpaceOnUse"
x1="196.63423"
y1="468.17209"
x2="170.13423"
y2="402.67206" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="417.6511"
inkscape:cy="345.62267"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="1920"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,-165.96284)"
style="display:inline">
<g
id="g3058"
transform="matrix(0.70142923,0,0,0.70142923,-172.43767,286.8878)">
<path
inkscape:connector-curvature="0"
id="path5084"
transform="translate(-522.78594,-97.359255)"
d="m 921.14258,351.92188 c -10.71472,0.3561 17.48242,40.65039 17.48242,40.65039 l -0.99805,38.58007 c -0.0632,-0.10181 -0.1163,-0.2052 -0.18164,-0.30664 -0.41273,0.4635 -0.8827,0.9276 -1.47656,1.39063 C 883.92622,472.81347 836.5,478.32226 756.5,516.32227 c -80,37.99997 -316.69239,159.29807 -343.5,147.5 -0.19217,-0.0846 -0.3462,-0.18445 -0.50195,-0.28321 -0.14711,0.0864 -0.35538,0.19871 -0.49805,0.28321 -0.0138,-0.0118 -0.0272,-0.0234 -0.041,-0.0352 l -0.0273,0.0156 c 20.65212,21.99316 41.34778,28.42752 134.68945,6.01954 l 67.87891,0 c 0,0 31.685,6.41255 73,41.25 56.21397,47.40048 70.15272,37.94645 213.83008,7.3789 120.72766,-25.68496 98.22343,-76.56575 107.07816,-168.1289 5.6329,-58.24749 15.6725,-114.94915 -35.90824,-161 -31.61176,-28.22275 -46.12465,-37.57431 -51.35742,-37.40039 z"
style="fill:#433737;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="scccccccccsccccssss"
inkscape:connector-curvature="0"
id="path5077"
transform="translate(-522.78594,-97.359255)"
d="m 766.6582,304.5 c -179.15881,0.002 -367.84961,155.86523 -367.84961,155.86523 -21.93235,32.98189 -41.23548,69.54864 -57.98242,109.60157 7.5036,28.04106 30.67382,59.21512 71.17383,93.85547 59.9519,-35.50497 512.63903,-236.02476 512.5,-244 95.7156,51.99999 -269.006,189 -269,189 -12.27104,5.04673 -14.55606,11.0677 -7.5,18 l 2.06445,1.76953 0.002,0 11.89062,10.1875 c -0.62249,0.15805 -1.26128,0.30706 -1.87305,0.48242 -47.26127,13.54738 -84.55325,23.64795 -114.41015,30.79101 L 615,669.82227 l 63.40625,-16.95508 38.59961,33.06445 c 38.18376,34.64823 37.84255,32.06806 141.42187,14.14258 C 964.16532,681.77523 962.3307,680.80807 974.39258,545.2168 984.45817,432.06647 1011.3318,377.81074 858.42773,320.35742 828.82733,309.23515 797.88772,304.49969 766.6582,304.5 z"
style="fill:#3d3d3d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5079"
transform="translate(-522.78594,-97.359255)"
d="m 924.5,419.82227 c 0.13868,7.95534 -450.25292,207.4789 -512.00586,243.71484 0.15695,0.0995 0.31224,0.19994 0.50586,0.28516 26.80761,11.79809 263.5,-109.50001 343.5,-147.5 80,-38.00001 127.42622,-43.50878 179.46875,-84.08594 0.5964,-0.46501 1.06842,-0.93101 1.48242,-1.39649 -2.56726,-3.98332 -6.80221,-7.67699 -12.95117,-11.01757 z"
style="fill:#826c5e;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path5101"
transform="translate(-522.78594,-97.359255)"
d="m 633.2832,328.9668 c -128.50884,43.87332 -234.47461,131.39843 -234.47461,131.39843 -21.86064,32.87406 -41.10756,69.31169 -57.8164,109.21094 l 0.008,-0.004 61.25,-46.25 c -0.31467,-30.27892 8.67871,-33.61166 108.5,-91 105.67745,-60.75512 109.87649,-54.6167 115.74609,-80.49805 1.83541,-8.09301 4.52898,-16.4514 6.78711,-22.85742 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5107"
transform="translate(-522.78594,-97.359255)"
d="m 640.70703,428.57422 c -3.04651,0.0756 -6.31444,0.73835 -9.96875,2.0918 -19.09188,7.07104 -141.89935,74.20682 -175.71484,98.99414 -48.59449,35.62053 -48.4375,14.14257 -48.4375,14.14257 l -4.24219,-20.85937 c 0,0 -0.0901,0.0489 -0.0937,0.0508 9.1e-4,0.11168 -10e-4,0.2157 0,0.32813 l -61.25,46.25 -0.008,0.004 c -0.0548,0.13093 -0.11124,0.25961 -0.16602,0.39063 7.5036,28.04104 30.67382,59.21512 71.17383,93.85547 0.14966,-0.0886 0.33959,-0.19447 0.49414,-0.28516 0.0169,-0.01 0.0397,-0.0213 0.0566,-0.0312 1.02546,-0.60112 2.16407,-1.25057 3.39844,-1.93945 0.2066,-0.11531 0.43415,-0.23971 0.64648,-0.35743 1.08032,-0.59888 2.2254,-1.22479 3.45118,-1.88476 0.32998,-0.17769 0.67334,-0.36095 1.01367,-0.54297 1.22538,-0.65535 2.51457,-1.33647 3.87109,-2.04687 0.32591,-0.17069 0.65104,-0.34183 0.98438,-0.51563 0.98003,-0.51099 2.03888,-1.05627 3.08203,-1.59375 1.50441,-0.77516 3.19823,-1.63034 4.83007,-2.45898 2.6812,-1.36148 5.48308,-2.77245 8.49219,-4.27149 1.45002,-0.72234 2.95192,-1.46789 4.47461,-2.2207 3.14575,-1.55527 6.43566,-3.16851 9.87696,-4.84766 1.7505,-0.85415 3.50304,-1.70917 5.32617,-2.59375 3.69907,-1.79476 7.57491,-3.665 11.55664,-5.57812 1.62203,-0.77935 3.19102,-1.53607 4.85742,-2.33399 4.85137,-2.32297 9.91021,-4.73306 15.11328,-7.20312 1.05862,-0.50256 2.06054,-0.98002 3.13281,-1.48828 6.27234,-2.97314 12.74159,-6.02841 19.44532,-9.18164 0.19493,-0.0917 0.37504,-0.1777 0.57031,-0.26954 0.88374,-0.4156 1.84183,-0.86083 2.73242,-1.27929 8.89106,-4.17765 18.33343,-8.58591 27.83008,-13.01563 9.48674,-4.42512 19.20352,-8.94432 29.15625,-13.5625 5.63004,-2.6124 11.17539,-5.18811 16.91992,-7.84765 11.03955,-5.11098 22.24511,-10.28776 33.57227,-15.51563 4.59686,-2.12162 9.06381,-4.18813 13.6875,-6.32031 31.79772,-14.66333 64.04275,-29.4992 94.89648,-43.72656 0.64347,-0.29672 1.23671,-0.57103 1.87891,-0.86719 -0.0661,-2.523 -0.5325,-5.27289 -1.4043,-8.3125 -2.95973,-10.3194 -36.14133,-35.93502 -56.06055,-50.55859 C 663.08118,438.83704 654.18972,428.94451 642,428.57812 c -0.42664,-0.0128 -0.85775,-0.0147 -1.29297,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
transform="matrix(0.89707316,-0.44188205,0.39545007,0.91848747,0,0)"
ry="4.5092516"
rx="4.7671914"
y="299.94894"
x="-63.730179"
height="22.140448"
width="42.955582"
id="rect5118"
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.4265933;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5120"
d="m 275.08906,417.33778 4.375,22.875 80.75,-60.625 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cssc"
inkscape:connector-curvature="0"
id="path5122"
d="m 281.58906,443.33778 91.75,-68.625 c 10.87423,-8.13345 34.03844,-10.26653 -9.25,21.375 -37.38734,27.32814 -82.5,47.25 -82.5,47.25 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path5124"
d="m 197.58906,448.96278 c 6.125,13 10.625,29.125 10.625,29.125 0,0 57.34269,-25.16319 68.25,-30.75 -0.13843,-9.48681 -3.52264,-22.72856 -8.375,-27.875 -27.125,3.75 -70.5,29.5 -70.5,29.5 z"
style="fill:url(#linearGradient3078);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566073;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccsccczc"
inkscape:connector-curvature="0"
id="path5138"
d="m 3.47828,341.26173 c 0,0 6.886406,9.46214 7.95495,30.22881 -9.7125082,0.38797 -22.45064,-1.59098 -48.96714,10.78339 -26.5165,12.37437 -35.70889,37.29989 -35.70889,37.29989 l -6.84404,-0.46967 -8.1731,-22.75242 c 0,0 5.196794,-22.7334 30.485095,-40.41753 C -32.486544,338.25007 3.47828,341.26173 3.47828,341.26173 z"
style="fill:#797979;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.42566061px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5140"
transform="translate(-522.78594,-97.359255)"
d="m 527.89648,441.94336 c -11.21543,-6.8e-4 -35.91089,1.15173 -54.02148,10.37891 -20.66776,10.53002 -34.76604,36.66892 -38.41016,44.00195 l 7.17383,19.9707 c 2.6388,-7.65898 11.92913,-28.82418 37.36133,-42.34765 27.46537,-14.60461 48.83613,-10.8705 53.86328,-9.67383 -1.11415,-11.22385 -3.86953,-18.48609 -5.74414,-22.32617 -0.0929,-1.7e-4 -0.12786,-0.004 -0.22266,-0.004 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="sccs"
inkscape:connector-curvature="0"
id="path5145"
transform="translate(-522.78594,-97.359255)"
d="m 485.25195,479.63281 c -26.5165,12.37437 -35.70886,37.34486 -35.70886,37.34486 9.75656,-6.29912 84.5483,-48.37571 84.5483,-48.37571 -6.04962,0.7682 -22.32294,-1.34352 -48.83944,11.03085 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path5151"
d="m -6.1035156,230.91992 c -19.3024674,3.60682 -35.0488854,16.31894 -52.6556354,24.21599 -51.094769,27.0536 -101.437299,55.94388 -149.051399,88.65901 -9.95415,5.51243 -22.54214,11.99271 -33.83984,6.61914 -6.38959,-3.90926 -7.96324,-11.94005 -8.66992,-18.82617 -15.28799,12.40039 -32.51253,23.07504 -46.6875,36.30469 11.43671,32.54466 37.53518,57.07166 61.90234,80.5625 1.79409,1.58773 4.14015,-3.28155 6.15485,-2.80815 C -144.1825,402.09598 -56.798635,363.92186 29.448769,323.50255 46.66114,315.61589 63.86767,307.71041 80.912109,299.46484 75.326356,287.31278 62.865961,280.7519 53.502952,271.87742 35.5688,257.98999 18.22755,242.94827 -1.484375,231.63672 c -1.4916064,-0.46547 -3.0527704,-0.75113 -4.6191406,-0.7168 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5162"
d="m -28.414062,137.02148 c -76.907488,29.50803 -148.819988,71.80459 -213.308758,122.89206 -13.55128,17.43946 -23.11685,37.54603 -33.88323,56.82187 -3.7754,7.32186 -7.34192,14.58222 -10.84707,22.04584 11.21464,-8.37958 22.86793,-16.47415 33.20898,-25.8125 -0.25698,-17.631 11.68533,-33.06792 26.42383,-41.59375 31.52229,-22.08766 66.11652,-39.23093 99.04413,-59.05073 30.395219,-17.37588 61.961588,-32.92482 91.295711,-52.0313 6.692064,-6.28955 7.910236,-15.49613 9.814453,-23.93359 l -0.935164,0.35421 -0.812882,0.30789 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5173"
d="m 152.77364,310.2307 c 1.1582,6.05599 2.3164,12.11198 3.4746,18.16797 21.37631,-16.04948 42.75261,-32.09896 64.12891,-48.14843 -22.5345,9.99349 -45.06901,19.98697 -67.60351,29.98046 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5187"
d="m 261.2834,263.28539 c -12.21657,2.16029 -20.42211,12.86093 -30.56476,19.12846 -18.40968,13.8199 -38.36778,28.59535 -55.81414,41.82076 29.28272,-15.22709 58.48771,-31.62916 82.88671,-54.0625 1.70896,-1.96865 4.73868,-4.48833 4.69532,-6.85547 -0.39767,-0.0641 -0.80252,-0.0596 -1.20313,-0.0312 z"
style="fill:#868686;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="path5192"
d="m 42.546875,449.04102 c 19.339052,15.73498 36.723013,34.10436 57.603515,47.67578 20.60808,9.36671 43.55773,2.08926 64.83959,-0.49809 35.57938,-6.15258 71.49952,-11.18454 106.39931,-20.59787 15.04923,-4.60526 29.72058,-14.93837 34.46618,-30.81811 9.43121,-25.52623 9.54274,-53.05503 12.87313,-79.81517 -0.62149,-4.24546 3.55982,-14.72991 -0.52003,-14.51534 -91.88723,32.85626 -183.77446,65.71253 -275.661695,98.5688 z"
style="fill:url(#linearGradient3080);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
<path
inkscape:connector-curvature="0"
id="rect5212"
d="m -27.103516,182.32422 c -10.397754,4.71799 -21.409505,9.91406 -30.929687,15.4375 2.508683,3.97971 3.88786,8.5168 5.707031,12.72266 10.007293,-5.84796 21.032198,-9.89858 31.039063,-15.81641 -1.598593,-4.02995 -3.118058,-9.77197 -5.816407,-12.34375 z"
style="fill:#868686;fill-opacity:1;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-502.6427"
y="633.16559"
id="text4473"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4475"
x="-502.6427"
y="633.16559"
style="font-size:32px">Button0</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4477"
y="337.89117"
x="-491.6427"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
y="337.89117"
x="-491.6427"
id="tspan4479"
sodipodi:role="line"
style="font-size:32px">Button1</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-484.6427"
y="453.61685"
id="text4481"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4483"
x="-484.6427"
y="453.61685"
style="font-size:32px">Button2</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4485"
y="235.48463"
x="-59.791931"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="235.48463"
x="-59.791931"
id="tspan4487"
sodipodi:role="line"
style="font-size:32px">Button3</tspan></text>
<text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-265.79193"
y="177.2103"
id="text4489"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4491"
x="-265.79193"
y="177.2103"
style="font-size:32px">Button4</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4493"
y="713.93604"
x="-229.79195"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
xml:space="preserve"><tspan
y="713.93604"
x="-229.79195"
id="tspan4495"
sodipodi:role="line"
style="font-size:32px">Button5</tspan></text>
<text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-499.79196"
y="209.66159"
id="text4497"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4499"
x="-499.79196"
y="209.66159"
style="font-size:32px">Button6</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -484.36582,336.67204 121,88"
id="path3082"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -480.36582,448.67204 148,-7"
id="path3084"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -492.36582,626.67204 130,-108"
id="path3086"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -375.36582,214.67204 133,180"
id="path3088"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -167.36582,192.67204 81,275"
id="path3092"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 34.63418,254.67204 -67,189"
id="path3094"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -152.36582,675.67204 85,-87"
id="path3096"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,557 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="750"
height="750"
viewBox="0 0 750.00004 749.99998"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="roccat-kone-xtd.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3581868"
inkscape:cx="337.88759"
inkscape:cy="511.56243"
inkscape:document-units="px"
inkscape:current-layer="layer4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="50"
fit-margin-left="50"
fit-margin-right="50"
fit-margin-bottom="50"
inkscape:window-width="1920"
inkscape:window-height="1099"
inkscape:window-x="1920"
inkscape:window-y="28"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Device"
inkscape:groupmode="layer"
id="layer1"
transform="translate(522.78594,-165.96284)"
style="display:inline">
<g
id="g3136"
transform="matrix(0.68876596,0,0,0.68876596,-231.95789,223.11559)">
<path
sodipodi:nodetypes="csc"
inkscape:connector-curvature="0"
id="path4770"
d="m -6.8766439,519.77381 c -32.5046101,10.85914 -64.2932331,9.07935 -55.9542041,-23.77308 18.883288,-74.39257 -57.845532,2.41084 -29.233145,-133.3763"
style="fill:none;stroke:#000000;stroke-width:29.49614906;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccsssssccc"
inkscape:connector-curvature="0"
id="path3661"
d="m -33.934887,422.04568 10.14038,-25.10953 C 52.122953,323.19727 160.74504,269.07207 269.83981,256.48052 c 114.24665,-13.18617 232.89306,-1.04277 284.3675,72.85307 67.68352,97.16539 16.07476,170.11753 -8.69176,195.56454 -20.05502,20.60604 -39.26023,38.76732 -57.46217,50.70193 -38.08063,24.96863 -99.02413,29.12078 -118.30443,27.5239 -56.28478,-4.66179 -227.65266,41.307 -235.6432,46.83891 L 32.219046,607.9527 C 4.8894737,559.61921 -21.751345,509.50644 -33.934887,422.04568 z"
style="fill:#293843;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4463"
d="m 520.63342,372.91486 c -22.02158,0.11026 -45.15654,9.22867 -63.99943,19.07328 -68.64532,35.8642 -269.2094,153.12888 -338.02986,180.28255 l -87.122352,34.37512 c 0.245863,0.43536 0.49112,0.87206 0.737105,1.30711 l 39.216027,16.16965 c 44.83999,-15.41316 98.86516,-40.41176 154.72423,-67.21674 90.48008,-43.41854 177.45369,-92.45774 236.96271,-121.89569 60.39622,-29.87684 105.87888,-24.18751 112.83284,44.85426 6.15884,-13.91293 10.75607,-30.17964 11.63778,-48.45529 -13.44827,-44.58801 -39.32739,-58.63259 -66.95905,-58.49425 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path4468"
d="m 460.17444,405.06363 c -25.33816,12.5814 -164.20311,89.16529 -247.36725,132.94909 -31.24494,16.55348 -62.91668,32.44366 -95.5461,46.08015 l 3.13236,9.65662 c 54.85379,-22.99389 108.07344,-49.78006 161.39646,-76.09146 64.31558,-32.64428 127.12882,-68.2385 192.32459,-99.13545 18.32983,-7.64259 38.30614,-12.8303 58.27155,-10.58417 14.47996,1.85097 28.06901,9.59531 37.24885,20.96153 6.66994,-53.74538 -76.10417,-40.33748 -109.46046,-23.83631 z"
style="fill:#00ff3a;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4545"
d="m 270.88842,559.80819 26.12051,4.09732 62.14289,-30.90074 c 11.97455,-20.17142 5.93562,-23.53024 5.29239,-31.92505 l -91.50713,47.4608 c -3.16993,2.58552 -6.42443,5.13123 -2.04866,11.26767 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="path4547"
d="m 392.10122,486.05615 c 1.23298,4.69552 4.04803,7.598 -1.19506,19.63307 l -9.73117,17.58438 80.75159,-31.4129 c 5.77716,-10.78358 11.4074,-21.61616 11.4384,-34.31516 -2.7867,-11.40006 -8.20083,-9.22506 -13.65779,-6.82888 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path4549"
d="M 20.837165,461.33753 26.414193,480.9345 62.94875,466.25238 55.307676,431.63187 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4551"
d="m 178.69842,365.35554 12.29201,31.24217 56.50906,-25.09617 -12.46274,-27.48628 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4553"
d="m 261.4987,335.64987 11.95056,26.63267 49.85089,-20.31594 12.80416,-3.41445 -6.82888,-14.16994 -12.97489,-3.41445 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
d="m 204.43745,364.0435 2.09895,5.60714 5.81901,-2.56255 0.64062,1.71134 -5.81901,2.56254 2.09895,5.60714 -1.75511,0.77292 -2.09894,-5.60715 -5.81902,2.56255 -0.64059,-1.71135 5.81898,-2.56254 -2.09892,-5.60714 1.75508,-0.7729 z"
id="path4560"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif"
inkscape:connector-curvature="0"
id="path4567"
d="m 305.42303,329.94388 4.03768,8.95391 -2.72436,1.22853 -4.03769,-8.95391 2.72437,-1.22853 z" />
<path
d="m 46.989112,448.7916 2.557622,11.39542 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56351 z"
id="path4569"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif"
inkscape:connector-curvature="0"
id="path4577"
d="m 42.643233,451.50777 2.557622,11.39545 -2.682847,1.56351 -2.557622,-11.39545 2.682847,-1.56351 z" />
<path
d="m 38.478433,454.34466 2.557622,11.39543 -2.682847,1.56354 -2.557622,-11.39545 2.682847,-1.56352 z"
id="path4579"
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif" />
<path
inkscape:connector-curvature="0"
id="path4581"
d="m 119.43841,465.4441 5.37199,3.74229 1.87114,-8.26926 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path4583"
d="m 99.218,376.23286 -2.29366,6.51884 6.33774,-3.25942 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4585"
d="m 370.13999,299.12951 c -0.43414,-0.004 -0.88599,0.004 -1.35658,0.0243 -114.61991,18.29248 -262.7613,57.8235 -362.6396132,162.97056 l -0.2413441,18.34924 -23.0804397,18.75305 c 0.295394,0.96107 0.592605,1.91666 0.892085,2.8672 L 6.8682998,485.78508 11.938416,498.5815 c 3.022522,1.91455 4.542353,4.99753 13.03731,2.65575 0,0 35.049508,-13.87527 66.878294,-31.62836 25.86269,-14.4254 169.13513,-92.29377 297.45122,-135.68783 3.53168,-1.85807 6.92052,-3.82383 2.89753,-11.3479 l -11.34789,-17.38339 c -1.68431,-3.27833 -4.20267,-6.0005 -10.71489,-6.06024 z m 0.85055,7.18994 c 0.76127,-0.0183 1.49621,0.14715 2.1413,0.68389 2.28062,2.60105 3.95393,5.73706 5.90572,8.6044 2.36789,3.85426 5.13602,7.51375 7.31692,11.43239 -2.00889,0.76437 -4.02217,1.5172 -6.0383,2.2622 -74.38121,26.47497 -146.51346,58.91354 -216.93155,94.53357 -23.7859,11.80119 -47.13201,24.45131 -70.49007,37.07193 -21.87976,12.03816 -44.368571,22.99172 -67.494965,32.39674 -2.178032,0.79387 -4.91012,2.49014 -7.139522,0.97798 -2.462342,-3.62775 -3.065109,-8.18739 -5.10326,-12.05744 -0.191754,-5.72806 0.125694,-11.45575 0.125574,-17.18406 19.24401,-19.99827 40.662677,-37.85032 63.501803,-53.60899 56.88977,-39.14613 121.81546,-65.28367 188.25625,-83.14833 34.45174,-9.02055 69.30996,-16.66573 104.56505,-21.77335 0.46215,-0.10291 0.9283,-0.17995 1.38505,-0.19093 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="czsccscc"
inkscape:connector-curvature="0"
id="path4590"
d="m 69.56866,436.43193 c 2.34022,-18.39325 11.0874,-31.41629 35.56456,-46.25604 24.47717,-14.83973 51.02774,-12.17822 62.53237,-11.10613 4.19739,0.39116 6.14741,2.1271 9.65751,8.20888 l 9.65751,18.10785 c -9.72905,-3.24303 -45.31306,0.55135 -63.36379,8.82104 -23.93977,10.96767 -32.63451,13.417 -49.78556,44.90031 z"
style="fill:#202427;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<text
transform="matrix(0.81792144,-0.30782972,0,1.2226113,0,0)"
sodipodi:linespacing="125%"
id="text4751"
y="544.12469"
x="541.47949"
style="font-size:19.26995659px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#838d96;fill-opacity:1;stroke:none;font-family:sans-serif;-inkscape-font-specification:sans-serif Bold"
xml:space="preserve"><tspan
y="544.12469"
x="541.47949"
id="tspan4753"
sodipodi:role="line">&gt;</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4759"
d="m 300.25264,556.5858 10.24335,-10.8622 0.29876,2.6035 -4.75887,5.05767 6.35939,-0.96032 0.72556,2.19804 z"
style="fill:#838d96;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
id="path4761"
d="m 175.51398,404.23374 c -14.95857,0.0867 -38.3591,3.7713 -51.89715,9.97357 -23.8618,10.93194 -32.57995,13.40905 -49.62048,44.60172 l 112.98222,-53.41898 -0.0122,-0.008 c -2.4337,-0.80767 -6.47543,-1.17722 -11.45245,-1.14838 z"
style="fill:#151d23;fill-opacity:1;fill-rule:evenodd;stroke:none"
inkscape:connector-curvature="0" />
<ellipse
sodipodi:ry="11.985341"
sodipodi:rx="11.98534"
sodipodi:cy="294.12094"
sodipodi:cx="-12.758862"
d="m -0.77352142,294.12094 c 0,6.61932 -5.36601958,11.98534 -11.98534058,11.98534 -6.61932,0 -11.98534,-5.36602 -11.98534,-11.98534 0,-6.61932 5.36602,-11.98534 11.98534,-11.98534 6.619321,0 11.98534058,5.36602 11.98534058,11.98534 z"
ry="11.985341"
rx="11.98534"
cy="294.12094"
cx="-12.758862"
id="path4352"
style="fill:#898989;fill-opacity:1;stroke:none;display:inline"
transform="translate(124.57988,108.29077)" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Leaders"
transform="translate(647.36582,-57.672066)"
style="display:inline">
<g
style="display:inline"
id="g4230"
transform="translate(-312.22243,78.703789)">
<text
sodipodi:linespacing="125%"
id="text4473"
y="547.70569"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4217"
y="547.70569"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button0</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4212"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4214"
style="font-size:32px">Button12</tspan></text>
</g>
<g
style="display:inline"
id="g4224"
transform="translate(-177.72019,47.152301)">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="6.9855804"
y="647.10291"
id="text4216"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="6.9855804"
y="647.10291"
id="tspan4218"
style="font-size:32px">Button3</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4220"
y="690.54315"
x="6.9855804"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4222"
y="690.54315"
x="6.9855804"
sodipodi:role="line"
style="font-size:32px">Button15</tspan></text>
</g>
<g
style="display:inline"
id="g4250"
transform="translate(-353.6901,52.306237)">
<text
sodipodi:linespacing="125%"
id="text4238"
y="645.63037"
x="270.96399"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4240"
y="645.63037"
x="270.96399"
sodipodi:role="line"
style="font-size:32px">Button4</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="270.96399"
y="689.07062"
id="text4242"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="270.96399"
y="689.07062"
id="tspan4244"
style="font-size:32px">Button16</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 426.30366,602.00857 72.8913,-163.45321"
id="path3163"
inkscape:connector-curvature="0"
transform="translate(-293.67572,5.365799)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 629.51576,602.74485 586.81177,393.64254"
id="path3165"
inkscape:connector-curvature="0"
transform="translate(-293.67572,5.365799)" />
</g>
<g
style="display:inline"
id="g4256"
transform="translate(-311.42639,-501.45091)">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="195.12758"
y="642.68524"
id="text4258"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="195.12758"
y="642.68524"
id="tspan4260"
style="font-size:32.00000171px">Button10</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4262"
y="686.12549"
x="195.12758"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4264"
y="686.12549"
x="195.12758"
sodipodi:role="line"
style="font-size:32.00000171px">Button22</tspan></text>
</g>
<g
style="display:inline"
transform="translate(-539.74217,-541.2965)"
id="g4266">
<text
sodipodi:linespacing="125%"
id="text4268"
y="642.68524"
x="195.12758"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4270"
y="642.68524"
x="195.12758"
sodipodi:role="line"
style="font-size:32px">Button9</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="195.12758"
y="686.12549"
id="text4272"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="195.12758"
y="686.12549"
id="tspan4274"
style="font-size:32px">Button21</tspan></text>
</g>
<g
style="display:inline"
transform="translate(-209.20512,184.48383)"
id="g4276">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4278"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4280"
style="font-size:32px">Button5</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4282"
y="591.14594"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4284"
y="591.14594"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button17</tspan></text>
</g>
<g
style="display:inline"
id="g4286"
transform="translate(-330.93429,-54.814789)">
<text
sodipodi:linespacing="125%"
id="text4288"
y="547.70569"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4290"
y="547.70569"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button11</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4292"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4294"
style="font-size:32px">Button23</tspan></text>
</g>
<g
style="display:inline"
transform="translate(-333.46977,-188.98667)"
id="g4338">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4340"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4342"
style="font-size:32px">Button1</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4344"
y="591.14594"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4346"
y="591.14594"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button13</tspan></text>
</g>
<g
style="display:inline"
id="g4348"
transform="translate(-264.96175,-314.68951)">
<text
sodipodi:linespacing="125%"
id="text4350"
y="547.70569"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4352"
y="547.70569"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button2</tspan></text>
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="591.14594"
id="text4354"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="591.14594"
id="tspan4356"
style="font-size:32px">Button14</tspan></text>
</g>
<g
style="display:inline"
transform="translate(-220.77251,-418.68304)"
id="g4358">
<text
xml:space="preserve"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
x="-157.20392"
y="547.70569"
id="text4360"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-157.20392"
y="547.70569"
id="tspan4362"
style="font-size:32px">Button6</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4364"
y="591.14594"
x="-157.20392"
style="font-size:40.00000381px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:'Sans, Normal'"
xml:space="preserve"><tspan
id="tspan4366"
y="591.14594"
x="-157.20392"
sodipodi:role="line"
style="font-size:32px">Button18</tspan></text>
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 250.33375,638.82236 373.2918,377.44447"
id="path3167"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 187.75032,550.46927 313.65347,442.97301"
id="path3171"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 170.0797,442.23674 318.07112,378.91702"
id="path3173"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 590.49315,144.78134 502.14006,287.61883"
id="path3175"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 403.47911,102.07734 437.34779,309.7071"
id="path3177"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 257.69651,135.20975 98.66095,183.33266"
id="path3179"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 207.62976,229.45305 365.19277,333.26793"
id="path3181"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 162.71694,318.54241 133.26591,29.45103"
id="path3183"
inkscape:connector-curvature="0"
transform="translate(-647.36582,57.672036)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.ratbag1"/>
<allow send_destination="org.freedesktop.ratbag1"/>
<allow receive_sender="org.freedesktop.ratbag1"/>
</policy>
<!-- allow everyone to talk to the daemon -->
<policy context="default">
<allow send_destination="org.freedesktop.ratbag1"/>
<allow receive_sender="org.freedesktop.ratbag1"/>
</policy>
</busconfig>

View File

@@ -0,0 +1,5 @@
[D-BUS Service]
Name=org.freedesktop.ratbag1
Exec=@bindir@/ratbagd
User=root
SystemdService=dbus-org.freedesktop.ratbag1.service

View File

@@ -0,0 +1,26 @@
<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<!--
WARNING: this file is for testing of libratbag during development.
If you don't know why this file is in your dbus configuration
folder, remove it.
-->
<busconfig>
<policy user="root">
<allow own="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
<allow send_destination="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
<allow receive_sender="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
</policy>
<!-- allow everyone to talk to the daemon -->
<policy context="default">
<allow send_destination="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
<allow receive_sender="org.freedesktop.ratbag_devel1_@ratbagd_sha@"/>
</policy>
</busconfig>

View File

@@ -1,28 +0,0 @@
PROJECT_NAME = @PACKAGE_NAME@
PROJECT_NUMBER = @PACKAGE_VERSION@
PROJECT_BRIEF = "A mouse configuration library"
JAVADOC_AUTOBRIEF = YES
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_ALL = YES
EXTRACT_STATIC = YES
MAX_INITIALIZER_LINES = 0
QUIET = YES
# Keep this list in sync with meson.build
INPUT = @top_srcdir@/src/libratbag.h \
@top_srcdir@/README.md
GENERATE_HTML = YES
HTML_TIMESTAMP = YES
USE_MATHJAX = YES
GENERATE_LATEX = NO
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = LIBRATBAG_ATTRIBUTE_PRINTF(f, \
a)= \
LIBRATBAG_ATTRIBUTE_DEPRECATED
HTML_HEADER = @top_srcdir@/doc/style/header.html
HTML_FOOTER = @top_srcdir@/doc/style/footer.html
HTML_EXTRA_STYLESHEET = @top_srcdir@/doc/style/customdoxygen.css \
@top_srcdir@/doc/style/bootstrap.css
USE_MDFILE_AS_MAINPAGE = README.md

View File

@@ -1,229 +0,0 @@
These licenses apply to the doxygen documentation HTML style only. They do
not apply or affect libratbag itself.
Apache: https://github.com/Velron/doxygen-bootstrapped/
MIT: https://bootswatch.com/paper/bootstrap.css
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The MIT License (MIT)
Copyright (c) 2011-2015 Twitter, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

7500
doc/style/bootstrap.css vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,255 +0,0 @@
h1, .h1, h2, .h2, h3, .h3{
font-weight: 200 !important;
}
#navrow1, #navrow2, #navrow3, #navrow4, #navrow5{
border-bottom: 1px solid #EEEEEE;
}
.adjust-right {
margin-left: 30px !important;
font-size: 1.15em !important;
}
.navbar{
border: 0px solid #222 !important;
}
/* Sticky footer styles
-------------------------------------------------- */
html,
body {
height: 100%;
/* The html and body elements cannot have any padding or margin. */
}
/* Wrapper for page content to push down footer */
#wrap {
min-height: 100%;
height: auto;
/* Negative indent footer by its height */
margin: 0 auto -60px;
/* Pad bottom by footer height */
padding: 0 0 60px;
}
/* Set the fixed height of the footer here */
#footer {
font-size: 0.9em;
padding: 8px 0px;
background-color: #f5f5f5;
}
.footer-row {
line-height: 44px;
}
#footer > .container {
padding-left: 15px;
padding-right: 15px;
}
.footer-follow-icon {
margin-left: 3px;
text-decoration: none !important;
}
.footer-follow-icon img {
width: 20px;
}
.footer-link {
padding-top: 5px;
display: inline-block;
color: #999999;
text-decoration: none;
}
.footer-copyright {
text-align: center;
}
@media (min-width: 992px) {
.footer-row {
text-align: left;
}
.footer-icons {
text-align: right;
}
}
@media (max-width: 991px) {
.footer-row {
text-align: center;
}
.footer-icons {
text-align: center;
}
}
/* DOXYGEN Code Styles
----------------------------------- */
a.qindex {
font-weight: bold;
}
a.qindexHL {
font-weight: bold;
background-color: #9CAFD4;
color: #ffffff;
border: 1px double #869DCA;
}
.contents a.qindexHL:visited {
color: #ffffff;
}
a.code, a.code:visited, a.line, a.line:visited {
color: #4665A2;
}
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
color: #4665A2;
}
/* @end */
dl.el {
margin-left: -1cm;
}
pre.fragment {
border: 1px solid #C4CFE5;
background-color: #FBFCFD;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
font-family: monospace, fixed;
font-size: 105%;
}
div.fragment {
padding: 4px 6px;
margin: 4px 8px 4px 2px;
border: 1px solid #C4CFE5;
}
div.line {
font-family: monospace, fixed;
font-size: 13px;
min-height: 13px;
line-height: 1.0;
text-wrap: unrestricted;
white-space: -moz-pre-wrap; /* Moz */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* IE 5.5+ */
text-indent: -53px;
padding-left: 53px;
padding-bottom: 0px;
margin: 0px;
-webkit-transition-property: background-color, box-shadow;
-webkit-transition-duration: 0.5s;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.5s;
-ms-transition-property: background-color, box-shadow;
-ms-transition-duration: 0.5s;
-o-transition-property: background-color, box-shadow;
-o-transition-duration: 0.5s;
transition-property: background-color, box-shadow;
transition-duration: 0.5s;
}
div.line.glow {
background-color: cyan;
box-shadow: 0 0 10px cyan;
}
span.lineno {
padding-right: 4px;
text-align: right;
border-right: 2px solid #0F0;
background-color: #E8E8E8;
white-space: pre;
}
span.lineno a {
background-color: #D8D8D8;
}
span.lineno a:hover {
background-color: #C8C8C8;
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
font-weight: bold;
}
div.groupText {
margin-left: 16px;
font-style: italic;
}
/* @group Code Colorization */
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
span.vhdldigit {
color: #ff00ff
}
span.vhdlchar {
color: #000000
}
span.vhdlkeyword {
color: #700070
}
span.vhdllogic {
color: #ff0000
}
blockquote {
background-color: #F7F8FB;
border-left: 2px solid #9CAFD4;
margin: 0 24px 0 4px;
padding: 0 12px 0 16px;
}

View File

@@ -1,26 +0,0 @@
<!-- HTML footer for doxygen 1.8.8-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
</div>
</div>
</div>
</div>
</div>
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
</a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

View File

@@ -1,42 +0,0 @@
<!-- HTML header for doxygen 1.8.8-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- For Mobile Devices -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>-->
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<link href="bootstrap.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="doxy-boot.js"></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand">$projectname $projectnumber</a>
</div>
</div>
</nav>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div class="content" id="content">
<div class="container">
<div class="row">
<div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
<div style="margin-bottom: 15px;">
<!-- end header part -->

View File

@@ -69,49 +69,69 @@ mouse:usb:v046dpc041:name:*:
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
# G5 2007
# http://support.logitech.com/en_us/product/g5-laser-mouse-product/specs
mouse:usb:v046dpc049:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_DPI_LIST=400;800;1600;2000
RATBAG_HIDPP10_PROFILE_COUNT=1
# G7
# http://support.logitech.com/en_us/product/g7-laser-cordless-mouse/specs
mouse:usb:v046dpc51a:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_PROFILE_COUNT=1
# G9
# http://support.logitech.com/en_us/product/g9-laser-mouse/specs
mouse:usb:v046dpc048:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_DPI_LIST=0;200;400;600;800;1000;1200;1400;1600;1800;2000;2200;2400;2600;2800;3000;3200
RATBAG_HIDPP10_PROFILE=G9
RATBAG_HIDPP10_PROFILE_COUNT=5
# G9x [Original]
# http://support.logitech.com/en_us/product/g9x-laser-mouse/specs
mouse:usb:v046dpc066:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G500
RATBAG_HIDPP10_PROFILE_COUNT=5
# G9x [Call of Duty MW3 Edition]
# http://support.logitech.com/en_us/product/laser-mouse-g9x/specs
mouse:usb:v046dpc249:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G500
RATBAG_HIDPP10_PROFILE_COUNT=5
# G300
mouse:usb:v046dpc246:name:*:
RATBAG_DRIVER=logitech_g300
RATBAG_SVG=logitech-g300.svg
# G403 over USB
mouse:usb:v046dpc082:name:*:
RATBAG_DRIVER=hidpp20
RATBAG_SVG=logitech-g403.svg
# G500
# http://support.logitech.com/en_us/product/gaming-mouse-g500/specs
mouse:usb:v046dpc068:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g500.svg
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G500
RATBAG_HIDPP10_PROFILE_COUNT=1
# G500s
# http://support.logitech.com/en_us/product/g500s-laser-gaming-mouse/specs
mouse:usb:v046dpc24e:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g500s.svg
RATBAG_HIDPP10_DPI=0:8200@50
RATBAG_HIDPP10_PROFILE=G500
RATBAG_HIDPP10_PROFILE_COUNT=1
# G502 Proteus Core over USB
mouse:usb:v046dpc07d:name:*:
@@ -124,33 +144,41 @@ mouse:usb:v046dpc332:name:*:
RATBAG_SVG=logitech-g502.svg
# G700 over USB
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
mouse:usb:v046dpc06b:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g700.svg
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G700
RATBAG_HIDPP10_PROFILE_COUNT=5
# G700 over wireless USB
# http://support.logitech.com/en_us/product/wireless-gaming-mouse-g700/specs
mouse:usb:v046dpc531:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_HIDPP10_DPI=0:5700@23.53
RATBAG_HIDPP10_PROFILE=G700
RATBAG_HIDPP10_INDEX=1
RATBAG_HIDPP10_PROFILE_COUNT=5
# G700s over USB
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
mouse:usb:v046dpc07c:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g700.svg
RATBAG_HIDPP10_DPI=0:8200@50
RATBAG_HIDPP10_PROFILE=G700
RATBAG_HIDPP10_PROFILE_COUNT=5
# G700s over wireless USB
# http://support.logitech.com/en_us/product/g700s-rechargable-wireless-gaming-mouse/specs
mouse:usb:v046dpc531:name:*:
RATBAG_DRIVER=hidpp10
RATBAG_SVG=logitech-g700.svg
RATBAG_HIDPP10_DPI=0:8200@50
RATBAG_HIDPP10_PROFILE=G700
RATBAG_HIDPP10_INDEX=1
RATBAG_HIDPP10_PROFILE_COUNT=5
# MX Master over unifying
mouse:usb:v046dp4041:name:*:
@@ -184,7 +212,7 @@ mouse:usb:v046dpc537:name:*:
mouse:usb:v046dpc081:name:*:
RATBAG_SVG=logitech-g900.svg
# G900 over wireless USB
# G900, G403 over wireless USB
mouse:usb:v046dpc539:name:*:
RATBAG_DRIVER=hidpp20
RATBAG_SVG=logitech-g900.svg

View File

@@ -1,10 +1,14 @@
project('libratbag', 'c', 'cpp',
version : '0.9.0',
version : '0.9.900',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ])
libratbag_version = meson.project_version().split('.')
git = find_program('git')
r = run_command('tools/ratbag-git-sha.sh')
ratbagd_sha = r.stdout().strip()
# We use libtool-version numbers because it's easier to understand.
# Before making a release, the libratbag_so_* and liblur_so_*
# numbers should be modified. The components are of the form C:R:A.
@@ -13,16 +17,11 @@ libratbag_version = meson.project_version().split('.')
# b) If interfaces have been changed or added, but binary compatibility has
# been preserved, change to C+1:0:A+1
# c) If the interface is the same as the previous version, change to C:R+1:A
libratbag_so_c=4
libratbag_so_r=3
libratbag_so_a=0
liblur_so_c=3
liblur_so_r=3
liblur_so_a=0
# convert to sonames
libratbag_so_version = '@0@.@1@.@2@'.format((libratbag_so_c - libratbag_so_a),
libratbag_so_a, libratbag_so_r)
liblur_so_version = '@0@.@1@.@2@'.format((liblur_so_c-liblur_so_a),
liblur_so_a, liblur_so_r)
@@ -38,11 +37,17 @@ add_project_arguments(cppflags, language: 'cpp')
# is generated at the end of this file
config_h = configuration_data()
config_h.set('_GNU_SOURCE', '1')
libratbag_data_dir = join_paths(get_option('prefix'),
get_option('datadir'),
'libratbag')
config_h.set_quoted('LIBRATBAG_DATA_DIR', libratbag_data_dir)
# dependencies
pkgconfig = import('pkgconfig')
dep_udev = dependency('libudev')
dep_libevdev = dependency('libevdev')
dep_libsystemd = dependency('libsystemd', version : '>=227')
dep_systemd = dependency('systemd')
dep_lm = cc.find_library('m')
#### libutil.a ####
@@ -115,9 +120,8 @@ pkgconfig.generate (
)
#### libratbag.so ####
install_headers('src/libratbag.h')
src_libratbag = [
'src/libratbag.h',
'src/driver-etekcity.c',
'src/driver-hidpp20.c',
'src/driver-hidpp10.c',
@@ -143,9 +147,6 @@ deps_libratbag = [
]
libratbag_version_h_config = configuration_data()
libratbag_version_h_config.set('LIBRATBAG_VERSION_MAJOR', libratbag_version[0])
libratbag_version_h_config.set('LIBRATBAG_VERSION_MINOR', libratbag_version[1])
libratbag_version_h_config.set('LIBRATBAG_VERSION_MICRO', libratbag_version[2])
libratbag_version_h_config.set_quoted('LIBRATBAG_VERSION', meson.project_version())
libratbag_version_h = configure_file(
@@ -154,16 +155,10 @@ libratbag_version_h = configure_file(
install: false,
)
mapfile = 'src/libratbag.sym'
version_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
lib_libratbag = shared_library('ratbag',
lib_libratbag = static_library('ratbag',
src_libratbag,
include_directories : include_directories('.'),
dependencies : deps_libratbag,
version : libratbag_so_version,
link_args : version_flag,
link_depends : mapfile,
install : true,
)
dep_libratbag = declare_dependency(
@@ -171,20 +166,6 @@ dep_libratbag = declare_dependency(
dependencies : deps_libratbag
)
pkgconfigdata = configuration_data()
pkgconfigdata.set('prefix', get_option('prefix'))
pkgconfigdata.set('libdir', get_option('libdir'))
pkgconfigdata.set('datadir', get_option('datadir'))
pkgconfigdata.set('includedir', get_option('includedir'))
pkgconfigdata.set('LIBRATBAG_VERSION', meson.project_version())
pkgconfigfile = configure_file(
input : 'src/libratbag.pc.in',
output : 'libratbag.pc',
configuration : pkgconfigdata,
install : true,
install_dir : get_option('libdir') + '/pkgconfig'
)
#### libshared.a ####
src_libshared = [
'tools/shared.c',
@@ -214,7 +195,7 @@ executable('ratbag-command',
src_ratbag_command,
dependencies : deps_ratbag_command,
include_directories : include_directories('src'),
install : true,
install : false,
)
man_config = configuration_data()
@@ -278,19 +259,31 @@ install_data('hwdb/70-libratbag-mouse.hwdb',
install_dir : udev_hwdb_dir)
#### svg files ####
svg_files = [
'data/etekcity.svg',
'data/logitech-g300.svg',
'data/logitech-g303.svg',
'data/logitech-g500s.svg',
'data/logitech-g502.svg',
'data/logitech-g700.svg',
'data/logitech-g900.svg',
'data/logitech-mx_master.svg',
'data/roccat-kone-xtd.svg'
default_svg_files = [
'data/default/etekcity.svg',
'data/default/logitech-g300.svg',
'data/default/logitech-g303.svg',
'data/default/logitech-g500s.svg',
'data/default/logitech-g502.svg',
'data/default/logitech-g700.svg',
'data/default/logitech-g900.svg',
'data/default/logitech-mx_master.svg',
'data/default/roccat-kone-xtd.svg'
]
install_data(svg_files,
install_dir : '@0@/libratbag'.format(get_option('datadir')))
install_data(default_svg_files,
install_dir : join_paths(get_option('datadir'), 'libratbag', 'default'))
gnome_svg_files = [
'data/gnome/logitech-g303.svg',
'data/gnome/logitech-g403.svg',
'data/gnome/logitech-g500.svg',
'data/gnome/logitech-g500s.svg',
'data/gnome/logitech-g502.svg',
'data/gnome/logitech-g700.svg',
'data/gnome/roccat-kone-xtd.svg',
]
install_data(gnome_svg_files,
install_dir : join_paths(get_option('datadir'), 'libratbag', 'gnome'))
#### tests ####
enable_tests = get_option('enable-tests')
@@ -298,11 +291,8 @@ if enable_tests
dep_check = dependency('check', version: '>= 0.9.10')
config_h.set('BUILD_TESTS', '1')
env_test = ['RATBAG_TEST=1']
valgrind_args = [ '--leak-check=full',
'--quiet',
'--error-exitcode=3',
'--suppressions=@0@/test/valgrind.suppressions'.format(meson.current_source_dir()) ]
env_test = environment()
env_test.set('RATBAG_TEST', '1')
test_context = executable('test-context',
['test/test-context.c'],
@@ -321,9 +311,21 @@ if enable_tests
dep_libutil],
include_directories : include_directories('src'),
install : false)
test('test-context', test_context, env : env_test, valgrind_args : valgrind_args)
test('test-device', test_device, env : env_test, valgrind_args : valgrind_args)
test('test-iconv-helper', test_iconv_helper, env : env_test, valgrind_args : valgrind_args)
test('test-context', test_context, env : env_test)
test('test-device', test_device, env : env_test)
test('test-iconv-helper', test_iconv_helper, env : env_test)
valgrind = find_program('valgrind')
valgrind_suppressions_file = join_paths(meson.source_root(), 'test', 'valgrind.suppressions')
add_test_setup('valgrind',
exe_wrapper : [
valgrind,
'--leak-check=full',
'--quiet',
'--error-exitcode=3',
'--suppressions=' + valgrind_suppressions_file ],
env : env_test,
timeout_multiplier: 5)
executable('test-build-cxx',
['test/build-cxx.cc'],
@@ -355,49 +357,129 @@ test('symbols-leak-test',
test_symbols_leak,
args : [ meson.current_source_dir() ])
#### documentation ####
enable_doc = get_option('enable-documentation')
#### ratbagd ####
src_ratbagd = [
'src/shared-macro.h',
'src/shared-rbtree.h',
'src/shared-rbtree.c',
'ratbagd/ratbagd.h',
'ratbagd/ratbagd.c',
'ratbagd/ratbagd-led.c',
'ratbagd/ratbagd-button.c',
'ratbagd/ratbagd-device.c',
'ratbagd/ratbagd-profile.c',
'ratbagd/ratbagd-resolution.c',
'src/libratbag-util.h',
'src/libratbag-util.c',
]
if enable_doc
cmd_doxygen = find_program('doxygen')
cmd_dot = find_program('dot')
deps_ratbagd = [
dep_udev,
dep_libsystemd,
dep_libratbag,
]
v = run_command(cmd_doxygen, ['--version']).stdout()
if not v.version_compare('>=1.8.3')
error('Doxygen $doxygen_version too old. ' +
'Doxygen 1.8.3+ required for documentation build. ' +
'Install required doxygen version or ' +
'disable the documentation using --disable-documentation')
executable('ratbagd',
src_ratbagd,
dependencies : deps_ratbagd,
include_directories : include_directories('src'),
install : true,
)
install_man('ratbagd/ratbagd.8')
#### ratbagd_devel ####
executable('ratbagd.devel',
src_ratbagd,
dependencies : deps_ratbagd,
include_directories : include_directories('src'),
install : false,
c_args : '-DRATBAG_DBUS_INTERFACE="ratbag_devel1_@0@"'.format(ratbagd_sha),
)
config_ratbagd_devel = configuration_data()
config_ratbagd_devel.set('ratbagd_sha', ratbagd_sha)
configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
output : 'org.freedesktop.ratbag_devel1.conf',
configuration : config_ratbagd_devel)
#### unit file ####
unitdir = get_option('systemd-unit-dir')
if unitdir == ''
libdir = get_option('libdir')
default_unitdir = dep_systemd.get_pkgconfig_variable('systemdsystemunitdir')
# Fedora uses lib64 but systemd is in lib. Hack around this so it
# works out of the box.
intended_unitdir = join_paths(get_option('prefix'), get_option('libdir'), 'systemd')
if get_option('prefix') == '/usr' and intended_unitdir != default_unitdir
message('
systemd unitdir libdir mismatch detected, changing unitdir to
@0@
or specify with
mesonconf -Dsystemd-unit-dir=<path>
See https://github.com/libratbag/libratbag/issues/188
'.format(default_unitdir))
unitdir = default_unitdir
else
unitdir = intended_unitdir
endif
v = run_command(cmd_dot, ['-V']).stderr()
v = v.split(' ')[4]
if v.version_compare('<2.26.0')
error('Graphviz dot $dot_version too old. ' +
'Graphviz 2.26+ required for documentation build. ' +
'Install required graphviz version or ' +
'disable the documentation using --disable-documentation')
endif
doc_config = configuration_data()
doc_config.set('PACKAGE_NAME', meson.project_name())
doc_config.set('PACKAGE_VERSION', meson.project_version())
doc_config.set('top_srcdir', meson.source_root())
doxyfile = configure_file(input : 'doc/libratbag.doxygen.in',
output : 'libratbag.doxygen',
configuration : doc_config,
install : false)
src_doxygen = [ doxyfile,
'src/libratbag.h',
'README.md']
custom_target('doxygen',
input : src_doxygen,
output : [ 'html' ],
command : [ cmd_doxygen, doxyfile ],
install : false,
build_by_default : true)
endif
config_bindir = configuration_data()
config_bindir.set('bindir', join_paths(get_option('prefix'), get_option('bindir')))
configure_file(input : 'ratbagd/ratbagd.service.in',
output : 'ratbagd.service',
configuration : config_bindir,
install_dir : unitdir)
dbusdir = get_option('dbus-root-dir')
if dbusdir == ''
dbusdir = join_paths(get_option('datadir'), 'dbus-1')
endif
configure_file(input : 'dbus/org.freedesktop.ratbag1.service.in',
output : 'org.freedesktop.ratbag1.service',
configuration : config_bindir,
install_dir : join_paths(dbusdir, 'system-services'))
install_data('dbus/org.freedesktop.ratbag1.conf',
install_dir : join_paths(dbusdir, 'system.d'))
#### tools ####
python = import('python3')
py3 = python.find_python()
custom_target('ratbagctl',
output : 'ratbagctl',
input : ['tools/ratbagctl.in', 'tools/ratbagd.py'],
build_by_default : true,
command : [py3, join_paths(meson.source_root(), 'tools', 'merge_ratbagd.py'),
'@INPUT@',
'--output', '@OUTPUT@',
'--version', meson.project_version()],
install: true,
install_dir: get_option('bindir'))
install_man('tools/ratbagctl.1')
config_ratbagctl_devel = configuration_data()
config_ratbagctl_devel.set('ratbagd_sha', ratbagd_sha)
config_ratbagctl_devel.set('MESON_BUILD_ROOT', meson.build_root())
configure_file(input : 'tools/ratbagctl.devel.in',
output : 'ratbagctl.devel',
configuration : config_ratbagctl_devel)
configure_file(input : 'tools/ratbagctl.test.in',
output : 'ratbagctl.test',
configuration : config_ratbagctl_devel)
ratbagctl_test = find_program(join_paths(meson.build_root(), 'ratbagctl.test'))
test('ratbagctl-test', ratbagctl_test, args: ['-v'])
configure_file(input : 'tools/toolbox.py',
output : 'toolbox.py',
configuration : config_ratbagctl_devel)
#### output files ####
configure_file(output: 'config.h', install: false, configuration: config_h)

View File

@@ -8,7 +8,12 @@ option('enable-tests',
value: true,
description: 'Build the tests (default=yes)')
option('enable-documentation',
type: 'boolean',
value: true,
description: 'Build the documentation (default=yes)')
option('systemd-unit-dir',
type : 'string',
default : '',
description : 'systemd unit directory [default=$libdir/systemd/system]')
option('dbus-root-dir',
type : 'string',
default : '',
description : 'dbus service directory [default=$datadir/dbus-1]')

12
ratbagd/.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
*.a
*.log
*.o
*.stamp
*.swp
*.trs
*~
.dirstamp
.libs/
/*.tar.xz
tags
__pycache__

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.ratbag1"/>
<allow send_destination="org.freedesktop.ratbag1"/>
<allow receive_sender="org.freedesktop.ratbag1"/>
</policy>
</busconfig>

513
ratbagd/ratbagd-button.c Normal file
View File

@@ -0,0 +1,513 @@
/***
This file is part of ratbagd.
Copyright 2016 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <linux/input.h>
#include "ratbagd.h"
#include "shared-macro.h"
#include "libratbag-util.h"
struct ratbagd_button {
struct ratbag_button *lib_button;
unsigned int index;
char *path;
};
static int ratbagd_button_get_type(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
enum ratbag_button_type t;
t = ratbag_button_get_type(button->lib_button);
return sd_bus_message_append(reply, "u", t);
}
static int ratbagd_button_get_button(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
unsigned int b;
b = ratbag_button_get_button(button->lib_button);
return sd_bus_message_append(reply, "u", b);
}
static int ratbagd_button_set_button(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
unsigned int map;
int r;
r = sd_bus_message_read(m, "u", &map);
if (r < 0)
return r;
if (map == 0 || map > 30)
return 0;
r = ratbag_button_set_button(button->lib_button, map);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"ButtonMapping",
NULL);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"ActionType",
NULL);
}
return r;
}
static int ratbagd_button_get_special(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
enum ratbag_button_action_special special;
special = ratbag_button_get_special(button->lib_button);
return sd_bus_message_append(reply, "u", special);
}
static int ratbagd_button_set_special(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
enum ratbag_button_action_special special;
int r;
r = sd_bus_message_read(m, "u", &special);
if (r < 0)
return r;
r = ratbag_button_set_special(button->lib_button, special);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"SpecialMapping",
NULL);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"ActionType",
NULL);
}
return r;
}
static int ratbagd_button_get_key(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
unsigned int key;
unsigned int modifiers[10] = {0};
size_t nmodifiers = ELEMENTSOF(modifiers);
size_t i;
int r;
/* Return an array with the first element the key, the rest
are modifiers (or 0 if unset). If no key is set, the array is
just [0] */
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
key = ratbag_button_get_key(button->lib_button,
modifiers,
&nmodifiers);
r = sd_bus_message_append(reply, "u", key);
if (r < 0)
return r;
if (key == 0)
nmodifiers = 0;
for (i = 0; i < nmodifiers; i++) {
r = sd_bus_message_append(reply, "u", modifiers[0]);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_button_set_key(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
unsigned int key;
size_t nmodifiers = 10;
unsigned int modifiers[nmodifiers];
int r;
/* Expect an array with the first element the key, the rest
are modifiers (or 0 if unset). */
r = sd_bus_message_enter_container(m, 'a', "u");
if (r < 0)
return r;
r = sd_bus_message_read(m, "u", &key);
if (r < 0)
return r;
nmodifiers = 0;
while ((r = sd_bus_message_read_basic(m, 'u',
&modifiers[nmodifiers++])) > 0)
;
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
r = ratbag_button_set_key(button->lib_button, key, modifiers, nmodifiers);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"KeyMapping",
NULL);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"ActionType",
NULL);
}
return r;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbag_button_macro *, ratbag_button_macro_unref);
static int ratbagd_button_get_macro(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
_cleanup_(ratbag_button_macro_unrefp) struct ratbag_button_macro *macro = NULL;
int r;
unsigned int idx;
r = sd_bus_message_open_container(reply, 'a', "(uu)");
if (r < 0)
return r;
macro = ratbag_button_get_macro(button->lib_button);
if (!macro)
goto out;
for (idx = 0; idx < ratbag_button_macro_get_num_events(macro); idx++) {
enum ratbag_macro_event_type type;
int value;
type = ratbag_button_macro_get_event_type(macro, idx);
switch (type) {
case RATBAG_MACRO_EVENT_INVALID:
abort();
break;
case RATBAG_MACRO_EVENT_NONE:
goto out;
case RATBAG_MACRO_EVENT_KEY_PRESSED:
case RATBAG_MACRO_EVENT_KEY_RELEASED:
value = ratbag_button_macro_get_event_key(macro, idx);
break;
case RATBAG_MACRO_EVENT_WAIT:
value = ratbag_button_macro_get_event_timeout(macro, idx);
break;
}
r = sd_bus_message_append(reply, "(uu)", type, value);
if (r < 0)
return r;
}
out:
return sd_bus_message_close_container(reply);
}
static int ratbagd_button_set_macro(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
unsigned int type, value;
int r, idx = 0;
_cleanup_(ratbag_button_macro_unrefp) struct ratbag_button_macro *macro = NULL;
r = sd_bus_message_enter_container(m, 'a', "(uu)");
if (r < 0)
return r;
macro = ratbag_button_macro_new("macro");
while ((r = sd_bus_message_read(m, "(uu)", &type, &value)) > 0) {
r = ratbag_button_macro_set_event(macro, idx++, type, value);
if (r < 0)
return r;
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
r = ratbag_button_set_macro(button->lib_button, macro);
if (r < 0)
return r;
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"Macro",
NULL);
sd_bus_emit_properties_changed(bus,
button->path,
RATBAGD_NAME_ROOT ".Button",
"ActionType",
NULL);
}
return r;
}
static int ratbagd_button_get_action_type(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
enum ratbag_button_action_type type;
type = ratbag_button_get_action_type(button->lib_button);
return sd_bus_message_append(reply, "u", type);
}
static int ratbagd_button_get_action_types(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
int r;
enum ratbag_button_action_type types[] = {
RATBAG_BUTTON_ACTION_TYPE_BUTTON,
RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
RATBAG_BUTTON_ACTION_TYPE_KEY,
RATBAG_BUTTON_ACTION_TYPE_MACRO
};
enum ratbag_button_action_type *t;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
ARRAY_FOR_EACH(types, t) {
if (!ratbag_button_has_action_type(button->lib_button, *t))
continue;
r = sd_bus_message_append(reply, "u", *t);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_button_disable(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_button *button = userdata;
int r;
r = sd_bus_message_read(m, "");
if (r < 0)
return r;
r = ratbag_button_disable(button->lib_button);
return sd_bus_reply_method_return(m, "u", r);
}
const sd_bus_vtable ratbagd_button_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_button, index), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Type", "u", ratbagd_button_get_type, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("ButtonMapping", "u",
ratbagd_button_get_button,
ratbagd_button_set_button,
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("SpecialMapping", "u",
ratbagd_button_get_special,
ratbagd_button_set_special,
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("KeyMapping", "au",
ratbagd_button_get_key,
ratbagd_button_set_key,
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("Macro", "a(uu)",
ratbagd_button_get_macro,
ratbagd_button_set_macro,
0, SD_BUS_VTABLE_UNPRIVILEGED | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ActionType", "u", ratbagd_button_get_action_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ActionTypes", "au", ratbagd_button_get_action_types, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Disable", "", "u", ratbagd_button_disable, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
int ratbagd_button_new(struct ratbagd_button **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_button *lib_button,
unsigned int index)
{
_cleanup_(ratbagd_button_freep) struct ratbagd_button *button = NULL;
char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1],
button_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
assert(out);
assert(lib_button);
button = zalloc(sizeof(*button));
button->lib_button = lib_button;
button->index = index;
sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile));
sprintf(button_buffer, "b%u", index);
r = sd_bus_path_encode_many(&button->path,
RATBAGD_OBJ_ROOT "/button/%/%/%",
ratbagd_device_get_name(device),
profile_buffer,
button_buffer);
if (r < 0)
return r;
*out = button;
button = NULL;
return 0;
}
const char *ratbagd_button_get_path(struct ratbagd_button *button)
{
assert(button);
return button->path;
}
struct ratbagd_button *ratbagd_button_free(struct ratbagd_button *button)
{
if (!button)
return NULL;
button->path = mfree(button->path);
button->lib_button = ratbag_button_unref(button->lib_button);
return mfree(button);
}

548
ratbagd/ratbagd-device.c Normal file
View File

@@ -0,0 +1,548 @@
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <libratbag.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "ratbagd.h"
#include "shared-macro.h"
#include "shared-rbtree.h"
#include "libratbag-util.h"
struct ratbagd_device {
struct ratbagd *ctx;
RBNode node;
char *name;
char *path;
struct ratbag_device *lib_device;
sd_bus_slot *profile_vtable_slot;
sd_bus_slot *profile_enum_slot;
unsigned int n_profiles;
struct ratbagd_profile **profiles;
};
#define ratbagd_device_from_node(_ptr) \
rbnode_of((_ptr), struct ratbagd_device, node)
static int ratbagd_device_find_profile(sd_bus *bus,
const char *path,
const char *interface,
void *userdata,
void **found,
sd_bus_error *error)
{
_cleanup_(freep) char *name = NULL;
struct ratbagd_device *device = userdata;
unsigned int index = 0;
int r;
r = sd_bus_path_decode_many(path,
RATBAGD_OBJ_ROOT "/profile/%/p%",
NULL,
&name);
if (r <= 0)
return r;
r = safe_atou(name, &index);
if (r < 0)
return 0;
if (index >= device->n_profiles || !device->profiles[index])
return 0;
*found = device->profiles[index];
return 1;
}
static int ratbagd_device_list_profiles(sd_bus *bus,
const char *path,
void *userdata,
char ***paths,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
struct ratbagd_profile *profile;
char **profiles;
unsigned int i;
profiles = zalloc((device->n_profiles + 1) * sizeof(char *));
for (i = 0; i < device->n_profiles; ++i) {
profile = device->profiles[i];
if (!profile)
continue;
profiles[i] = strdup_safe(ratbagd_profile_get_path(profile));
}
profiles[i] = NULL;
*paths = profiles;
return 1;
}
static int ratbagd_device_get_device_name(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
const char *name;
name = ratbag_device_get_name(device->lib_device);
if (!name) {
log_error("Unable to fetch name for %s\n",
ratbagd_device_get_name(device));
name = "";
}
return sd_bus_message_append(reply, "s", name);
}
static int ratbagd_device_get_svg(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
const char *svg;
svg = ratbag_device_get_svg_name(device->lib_device);
if (!svg) {
log_error("Unable to fetch SVG for %s\n",
ratbagd_device_get_name(device));
svg = "";
}
return sd_bus_message_append(reply, "s", svg);
}
static int ratbagd_device_get_theme_svg(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
char svg_path[PATH_MAX] = {0};
const char *theme;
const char *svg;
int r;
r = sd_bus_message_read(m, "s", &theme);
if (r < 0)
return r;
svg = ratbag_device_get_svg_name(device->lib_device);
if (!svg) {
log_error("Unable to fetch SVG for %s\n",
ratbagd_device_get_name(device));
goto out;
}
sprintf(svg_path, "%s/%s/%s", LIBRATBAG_DATA_DIR, theme, svg);
out:
return sd_bus_reply_method_return(m, "s", svg_path);
}
static int ratbagd_device_get_profiles(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
struct ratbagd_profile *profile;
unsigned int i;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
for (i = 0; i < device->n_profiles; ++i) {
profile = device->profiles[i];
if (!profile)
continue;
r = sd_bus_message_append(reply,
"o",
ratbagd_profile_get_path(profile));
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_device_commit(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
int r;
r = ratbag_device_commit(device->lib_device);
return sd_bus_reply_method_return(m, "u", r);
}
static int
ratbagd_device_get_capabilities(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_device *device = userdata;
struct ratbag_device *lib_device = device->lib_device;
enum ratbag_device_capability cap;
enum ratbag_device_capability caps[] = {
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
RATBAG_DEVICE_CAP_RESOLUTION,
RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION,
RATBAG_DEVICE_CAP_PROFILE,
RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE,
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
RATBAG_DEVICE_CAP_BUTTON,
RATBAG_DEVICE_CAP_BUTTON_KEY,
RATBAG_DEVICE_CAP_BUTTON_MACROS,
RATBAG_DEVICE_CAP_LED,
};
int r;
size_t i;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
for (i = 0; i < ELEMENTSOF(caps); i++) {
cap = caps[i];
if (ratbag_device_has_capability(lib_device, cap)) {
r = sd_bus_message_append(reply, "u", cap);
if (r < 0)
return r;
}
}
return sd_bus_message_close_container(reply);
}
const sd_bus_vtable ratbagd_device_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, name), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Svg", "s", ratbagd_device_get_svg, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetSvg", "s", "s", ratbagd_device_get_theme_svg, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
int ratbagd_device_new(struct ratbagd_device **out,
struct ratbagd *ctx,
const char *name,
struct ratbag_device *lib_device)
{
_cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL;
struct ratbag_profile *profile;
unsigned int i;
int r;
assert(out);
assert(ctx);
assert(name);
device = zalloc(sizeof(*device));
device->ctx = ctx;
rbnode_init(&device->node);
device->lib_device = ratbag_device_ref(lib_device);
device->name = strdup_safe(name);
r = sd_bus_path_encode(RATBAGD_OBJ_ROOT "/device",
device->name,
&device->path);
if (r < 0)
return r;
device->n_profiles = ratbag_device_get_num_profiles(device->lib_device);
device->profiles = zalloc(device->n_profiles * sizeof(*device->profiles));
log_verbose("%s: \"%s\", %d profiles\n",
name,
ratbag_device_get_name(lib_device),
device->n_profiles);
for (i = 0; i < device->n_profiles; ++i) {
profile = ratbag_device_get_profile(device->lib_device, i);
if (!profile)
continue;
r = ratbagd_profile_new(&device->profiles[i],
device,
profile,
i);
if (r < 0) {
errno = -r;
log_error("Cannot allocate profile for '%s': %m\n",
device->name);
}
}
*out = device;
device = NULL;
return 0;
}
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device)
{
unsigned int i;
if (!device)
return NULL;
assert(!ratbagd_device_linked(device));
for (i = 0; i < device->n_profiles; ++i)
device->profiles[i] = ratbagd_profile_free(device->profiles[i]);
device->profiles = mfree(device->profiles);
device->lib_device = ratbag_device_unref(device->lib_device);
device->path = mfree(device->path);
device->name = mfree(device->name);
assert(!device->lib_device); /* ratbag yields !NULL if still pinned */
return mfree(device);
}
const char *ratbagd_device_get_name(struct ratbagd_device *device)
{
assert(device);
return device->name;
}
const char *ratbagd_device_get_path(struct ratbagd_device *device)
{
assert(device);
return device->path;
}
unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device)
{
assert(device);
return ratbag_device_get_num_buttons(device->lib_device);
}
unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device)
{
assert(device);
return ratbag_device_get_num_leds(device->lib_device);
}
bool ratbagd_device_linked(struct ratbagd_device *device)
{
return device && rbnode_linked(&device->node);
}
void ratbagd_device_link(struct ratbagd_device *device)
{
_cleanup_(freep) char *prefix = NULL;
struct ratbagd_device *iter;
RBNode **node, *parent;
int r, v;
unsigned int i;
assert(device);
assert(!ratbagd_device_linked(device));
/* find place to link it to */
parent = NULL;
node = &device->ctx->device_map.root;
while (*node) {
parent = *node;
iter = ratbagd_device_from_node(parent);
v = strcmp(device->name, iter->name);
/* if there's a duplicate, the caller screwed up */
assert(v != 0);
if (v < 0)
node = &parent->left;
else /* if (v > 0) */
node = &parent->right;
}
/* link into context */
rbtree_add(&device->ctx->device_map, parent, node, &device->node);
++device->ctx->n_devices;
/* register profile interfaces */
r = sd_bus_path_encode_many(&prefix,
RATBAGD_OBJ_ROOT "/profile/%",
device->name);
if (r >= 0) {
r = sd_bus_add_fallback_vtable(device->ctx->bus,
&device->profile_vtable_slot,
prefix,
RATBAGD_NAME_ROOT ".Profile",
ratbagd_profile_vtable,
ratbagd_device_find_profile,
device);
if (r >= 0)
r = sd_bus_add_node_enumerator(device->ctx->bus,
&device->profile_enum_slot,
prefix,
ratbagd_device_list_profiles,
device);
}
if (r < 0) {
errno = -r;
log_error("Cannot register profile interfaces for '%s': %m\n",
device->name);
return;
}
for (i = 0; i < device->n_profiles; i++) {
r = ratbagd_profile_register_resolutions(device->ctx->bus,
device,
device->profiles[i]);
if (r < 0) {
log_error("Cannot register resolutions for '%s': %m\n",
device->name);
}
r = ratbagd_profile_register_buttons(device->ctx->bus,
device,
device->profiles[i]);
if (r < 0) {
log_error("Cannot register buttons for '%s': %m\n",
device->name);
}
r = ratbagd_profile_register_leds(device->ctx->bus,
device,
device->profiles[i]);
if (r < 0) {
log_error("Cannot register leds for '%s': %m\n",
device->name);
}
}
}
void ratbagd_device_unlink(struct ratbagd_device *device)
{
if (!ratbagd_device_linked(device))
return;
device->profile_enum_slot = sd_bus_slot_unref(device->profile_enum_slot);
device->profile_vtable_slot = sd_bus_slot_unref(device->profile_vtable_slot);
/* unlink from context */
--device->ctx->n_devices;
rbtree_remove(&device->ctx->device_map, &device->node);
rbnode_init(&device->node);
}
struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx,
const char *name)
{
struct ratbagd_device *device;
RBNode *node;
int v;
assert(ctx);
assert(name);
node = ctx->device_map.root;
while (node) {
device = ratbagd_device_from_node(node);
v = strcmp(name, device->name);
if (!v)
return device;
else if (v < 0)
node = node->left;
else /* if (v > 0) */
node = node->right;
}
return NULL;
}
struct ratbagd_device *ratbagd_device_first(struct ratbagd *ctx)
{
struct RBNode *node;
assert(ctx);
node = rbtree_first(&ctx->device_map);
return node ? ratbagd_device_from_node(node) : NULL;
}
struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device)
{
struct RBNode *node;
assert(device);
node = rbnode_next(&device->node);
return node ? ratbagd_device_from_node(node) : NULL;
}
int ratbagd_for_each_profile_signal(sd_bus *bus,
struct ratbagd_device *device,
int (*func)(sd_bus *bus,
struct ratbagd_profile *profile))
{
int rc = 0;
for (size_t i = 0; rc == 0 && i < device->n_profiles; i++)
rc = func(bus, device->profiles[i]);
return rc;
}

316
ratbagd/ratbagd-led.c Normal file
View File

@@ -0,0 +1,316 @@
/***
This file is part of ratbagd.
Copyright 2017 Jente Hidskes <hjdskes@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <systemd/sd-bus.h>
#include "ratbagd.h"
#include "shared-macro.h"
#include "libratbag-util.h"
struct ratbagd_led {
struct ratbag_led *lib_led;
unsigned int index;
char *path;
};
static int ratbagd_led_get_mode(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
enum ratbag_led_mode mode;
mode = ratbag_led_get_mode(led->lib_led);
return sd_bus_message_append(reply, "u", mode);
}
static int ratbagd_led_set_mode(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
enum ratbag_led_mode mode;
int r;
r = sd_bus_message_read(m, "u", &mode);
if (r < 0)
return r;
r = ratbag_led_set_mode(led->lib_led, mode);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
led->path,
RATBAGD_NAME_ROOT ".Led",
"Mode",
NULL);
}
return r;
}
static int ratbagd_led_get_type(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
enum ratbag_led_type type;
type = ratbag_led_get_type(led->lib_led);
return sd_bus_message_append(reply, "u", type);
}
static int ratbagd_led_get_color(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
struct ratbag_color c;
c = ratbag_led_get_color(led->lib_led);
return sd_bus_message_append(reply, "(uuu)", c.red, c.green, c.blue);
}
static int ratbagd_led_set_color(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
struct ratbag_color c;
int r;
r = sd_bus_message_read(m, "(uuu)", &c.red, &c.green, &c.blue);
if (r < 0)
return r;
if (c.red > 255 || c.green > 255 || c.blue > 255)
return RATBAG_ERROR_VALUE;
r = ratbag_led_set_color(led->lib_led, c);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
led->path,
RATBAGD_NAME_ROOT ".Led",
"Color",
NULL);
}
return r;
}
static int ratbagd_led_get_effect_rate(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
int rate;
rate = ratbag_led_get_effect_rate(led->lib_led);
return sd_bus_message_append(reply, "u", rate);
}
static int ratbagd_led_set_effect_rate(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
unsigned int rate;
int r;
r = sd_bus_message_read(m, "u", &rate);
if (r < 0)
return r;
if (rate < 100 || rate > 20000)
return 0;
r = ratbag_led_set_effect_rate(led->lib_led, rate);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
led->path,
RATBAGD_NAME_ROOT ".Led",
"EffectRate",
NULL);
}
return r;
}
static int ratbagd_led_get_brightness(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
unsigned int brightness;
brightness = ratbag_led_get_brightness(led->lib_led);
return sd_bus_message_append(reply, "u", brightness);
}
static int ratbagd_led_set_brightness(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_led *led = userdata;
unsigned int brightness;
int r;
r = sd_bus_message_read(m, "u", &brightness);
if (r < 0)
return r;
if (brightness > 255)
return 0;
r = ratbag_led_set_brightness(led->lib_led, brightness);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
led->path,
RATBAGD_NAME_ROOT ".Led",
"Brightness",
NULL);
}
return r;
}
const sd_bus_vtable ratbagd_led_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_led, index), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("Mode", "u",
ratbagd_led_get_mode,
ratbagd_led_set_mode, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Type", "u", ratbagd_led_get_type, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("Color", "(uuu)",
ratbagd_led_get_color, ratbagd_led_set_color, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("EffectRate", "u",
ratbagd_led_get_effect_rate, ratbagd_led_set_effect_rate, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("Brightness", "u",
ratbagd_led_get_brightness, ratbagd_led_set_brightness, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_VTABLE_END,
};
int ratbagd_led_new(struct ratbagd_led **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_led *lib_led,
unsigned int index)
{
_cleanup_(ratbagd_led_freep) struct ratbagd_led *led = NULL;
char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1],
led_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
assert(out);
assert(lib_led);
led = zalloc(sizeof(*led));
led->lib_led = lib_led;
led->index = index;
sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile));
sprintf(led_buffer, "l%u", index);
r = sd_bus_path_encode_many(&led->path,
RATBAGD_OBJ_ROOT "/led/%/%/%",
ratbagd_device_get_name(device),
profile_buffer,
led_buffer);
if (r < 0)
return r;
*out = led;
led = NULL;
return 0;
}
const char *ratbagd_led_get_path(struct ratbagd_led *led)
{
assert(led);
return led->path;
}
struct ratbagd_led *ratbagd_led_free(struct ratbagd_led *led)
{
if (!led)
return NULL;
led->path = mfree(led->path);
led->lib_led = ratbag_led_unref(led->lib_led);
return mfree(led);
}

713
ratbagd/ratbagd-profile.c Normal file
View File

@@ -0,0 +1,713 @@
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "ratbagd.h"
#include "libratbag-util.h"
#include "shared-macro.h"
#include "libratbag-util.h"
struct ratbagd_profile {
struct ratbagd_device *device;
struct ratbag_profile *lib_profile;
unsigned int index;
char *path;
sd_bus_slot *resolution_vtable_slot;
sd_bus_slot *resolution_enum_slot;
unsigned int n_resolutions;
struct ratbagd_resolution **resolutions;
sd_bus_slot *button_vtable_slot;
sd_bus_slot *button_enum_slot;
unsigned int n_buttons;
struct ratbagd_button **buttons;
sd_bus_slot *led_vtable_slot;
sd_bus_slot *led_enum_slot;
unsigned int n_leds;
struct ratbagd_led **leds;
};
static int ratbagd_profile_find_resolution(sd_bus *bus,
const char *path,
const char *interface,
void *userdata,
void **found,
sd_bus_error *error)
{
_cleanup_(freep) char *name = NULL;
struct ratbagd_profile *profile = userdata;
unsigned int index = 0;
int r;
r = sd_bus_path_decode_many(path,
RATBAGD_OBJ_ROOT "/resolution/%/p%/r%",
NULL,
NULL,
&name);
if (r <= 0)
return r;
r = safe_atou(name, &index);
if (r < 0)
return 0;
if (index >= profile->n_resolutions || !profile->resolutions[index])
return 0;
*found = profile->resolutions[index];
return 1;
}
static int ratbagd_profile_get_resolutions(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_resolution *resolution;
unsigned int i;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
for (i = 0; i < profile->n_resolutions; ++i) {
resolution = profile->resolutions[i];
if (!resolution)
continue;
r = sd_bus_message_append(reply,
"o",
ratbagd_resolution_get_path(resolution));
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_profile_get_buttons(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_button *button;
unsigned int i;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
for (i = 0; i < profile->n_buttons; ++i) {
button = profile->buttons[i];
if (!button)
continue;
r = sd_bus_message_append(reply,
"o",
ratbagd_button_get_path(button));
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_profile_get_leds(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_led *led;
unsigned int i;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
for (i = 0; i < profile->n_leds; ++i) {
led = profile->leds[i];
if (!led)
continue;
r = sd_bus_message_append(reply,
"o",
ratbagd_led_get_path(led));
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_profile_is_active(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
bool is_active;
is_active = !!ratbag_profile_is_active(profile->lib_profile);
return sd_bus_message_append(reply, "b", is_active);
}
static int ratbagd_profile_find_button(sd_bus *bus,
const char *path,
const char *interface,
void *userdata,
void **found,
sd_bus_error *error)
{
_cleanup_(freep) char *name = NULL;
struct ratbagd_profile *profile = userdata;
unsigned int index = 0;
int r;
r = sd_bus_path_decode_many(path,
RATBAGD_OBJ_ROOT "/button/%/p%/b%",
NULL,
NULL,
&name);
if (r <= 0)
return r;
r = safe_atou(name, &index);
if (r < 0)
return 0;
if (index >= profile->n_buttons || !profile->buttons[index])
return 0;
*found = profile->buttons[index];
return 1;
}
static int ratbagd_profile_find_led(sd_bus *bus,
const char *path,
const char *interface,
void *userdata,
void **found,
sd_bus_error *error)
{
_cleanup_(freep) char *name = NULL;
struct ratbagd_profile *profile = userdata;
unsigned int index = 0;
int r;
r = sd_bus_path_decode_many(path,
RATBAGD_OBJ_ROOT "/led/%/p%/l%",
NULL,
NULL,
&name);
if (r <= 0)
return r;
r = safe_atou(name, &index);
if (r < 0)
return 0;
if (index >= profile->n_leds || !profile->leds[index])
return 0;
*found = profile->leds[index];
return 1;
}
static int ratbagd_profile_active_signal_cb(sd_bus *bus,
struct ratbagd_profile *profile)
{
struct ratbag_profile *lib_profile = profile->lib_profile;
/* FIXME: we should cache is active and only send the signal for
* those profiles where it changed */
(void) sd_bus_emit_signal(bus,
profile->path,
RATBAGD_NAME_ROOT ".Profile",
"IsActive",
"b",
ratbag_profile_is_active(lib_profile));
return 0;
}
static int ratbagd_profile_set_active(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
int r;
r = sd_bus_message_read(m, "");
if (r < 0)
return r;
ratbagd_for_each_profile_signal(sd_bus_message_get_bus(m),
profile->device,
ratbagd_profile_active_signal_cb);
return sd_bus_reply_method_return(m, "u",
ratbag_profile_set_active(profile->lib_profile));
}
static int
ratbagd_profile_set_enabled(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
bool enabled;
int r;
r = sd_bus_message_read(m, "b", &enabled);
if (r < 0)
return r;
r = ratbag_profile_set_enabled(profile->lib_profile, enabled);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
profile->path,
RATBAGD_NAME_ROOT ".Profile",
"Enabled",
NULL);
}
return r;
}
static int
ratbagd_profile_is_enabled(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
bool enabled = ratbag_profile_is_enabled(profile->lib_profile) != 0;
return sd_bus_message_append(reply, "b", enabled);
}
const sd_bus_vtable ratbagd_profile_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_WRITABLE_PROPERTY("Enabled", "b",
ratbagd_profile_is_enabled,
ratbagd_profile_set_enabled, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_profile, index), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Resolutions", "ao", ratbagd_profile_get_resolutions, 0, 0),
SD_BUS_PROPERTY("Buttons", "ao", ratbagd_profile_get_buttons, 0, 0),
SD_BUS_PROPERTY("Leds", "ao", ratbagd_profile_get_leds, 0, 0),
SD_BUS_PROPERTY("IsActive", "b", ratbagd_profile_is_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD("SetActive", "", "u", ratbagd_profile_set_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
int ratbagd_profile_new(struct ratbagd_profile **out,
struct ratbagd_device *device,
struct ratbag_profile *lib_profile,
unsigned int index)
{
_cleanup_(ratbagd_profile_freep) struct ratbagd_profile *profile = NULL;
struct ratbag_resolution *resolution;
struct ratbag_button *button;
struct ratbag_led *led;
char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
unsigned int i;
int r;
assert(out);
assert(lib_profile);
profile = zalloc(sizeof(*profile));
profile->device = device;
profile->lib_profile = lib_profile;
profile->index = index;
sprintf(index_buffer, "p%u", index);
r = sd_bus_path_encode_many(&profile->path,
RATBAGD_OBJ_ROOT "/profile/%/%",
ratbagd_device_get_name(device),
index_buffer);
if (r < 0)
return r;
profile->n_resolutions = ratbag_profile_get_num_resolutions(profile->lib_profile);
profile->resolutions = zalloc(profile->n_resolutions * sizeof(*profile->resolutions));
profile->n_buttons = ratbagd_device_get_num_buttons(device);
profile->buttons = zalloc(profile->n_buttons * sizeof(*profile->buttons));
profile->n_leds = ratbagd_device_get_num_leds(device);
profile->leds = zalloc(profile->n_leds * sizeof(*profile->leds));
for (i = 0; i < profile->n_resolutions; ++i) {
resolution = ratbag_profile_get_resolution(profile->lib_profile, i);
if (!resolution)
continue;
r = ratbagd_resolution_new(&profile->resolutions[i],
device,
profile,
resolution,
i);
if (r < 0) {
errno = -r;
log_error("Cannot allocate resolution for '%s': %m\n",
ratbagd_device_get_name(device));
}
}
for (i = 0; i < profile->n_buttons; ++i) {
button = ratbag_profile_get_button(profile->lib_profile, i);
if (!button)
continue;
r = ratbagd_button_new(&profile->buttons[i],
device,
profile,
button,
i);
if (r < 0) {
errno = -r;
log_error("Cannot allocate button for '%s': %m\n",
ratbagd_device_get_name(device));
}
}
for (i = 0; i < profile->n_leds; ++i) {
led = ratbag_profile_get_led(profile->lib_profile, i);
if (!led)
continue;
r = ratbagd_led_new(&profile->leds[i],
device,
profile,
led,
i);
if (r < 0) {
errno = -r;
log_error("Cannot allocate led for '%s': %m\n",
ratbagd_device_get_name(device));
}
}
*out = profile;
profile = NULL;
return 0;
}
struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile)
{
unsigned int i;
if (!profile)
return NULL;
profile->resolution_vtable_slot = sd_bus_slot_unref(profile->resolution_vtable_slot);
profile->resolution_enum_slot = sd_bus_slot_unref(profile->resolution_enum_slot);
profile->button_vtable_slot = sd_bus_slot_unref(profile->button_vtable_slot);
profile->button_enum_slot = sd_bus_slot_unref(profile->button_enum_slot);
profile->led_vtable_slot = sd_bus_slot_unref(profile->led_vtable_slot);
profile->led_enum_slot = sd_bus_slot_unref(profile->led_enum_slot);
for (i = 0; i< profile->n_leds; ++i)
ratbagd_led_free(profile->leds[i]);
for (i = 0; i< profile->n_buttons; ++i)
ratbagd_button_free(profile->buttons[i]);
for (i = 0; i< profile->n_resolutions; ++i)
ratbagd_resolution_free(profile->resolutions[i]);
mfree(profile->leds);
mfree(profile->buttons);
mfree(profile->resolutions);
profile->path = mfree(profile->path);
profile->lib_profile = ratbag_profile_unref(profile->lib_profile);
return mfree(profile);
}
const char *ratbagd_profile_get_path(struct ratbagd_profile *profile)
{
assert(profile);
return profile->path;
}
unsigned int ratbagd_profile_get_index(struct ratbagd_profile *profile)
{
assert(profile);
return profile->index;
}
static int ratbagd_profile_list_resolutions(sd_bus *bus,
const char *path,
void *userdata,
char ***paths,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_resolution *resolution;
char **resolutions;
unsigned int i;
resolutions = zalloc((profile->n_resolutions + 1) * sizeof(char *));
for (i = 0; i < profile->n_resolutions; ++i) {
resolution = profile->resolutions[i];
if (!resolution)
continue;
resolutions[i] = strdup_safe(ratbagd_resolution_get_path(resolution));
}
resolutions[i] = NULL;
*paths = resolutions;
return 1;
}
int ratbagd_profile_register_resolutions(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile)
{
_cleanup_(freep) char *prefix = NULL;
char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
sprintf(index_buffer, "p%u", profile->index);
/* register resolution interfaces */
r = sd_bus_path_encode_many(&prefix,
RATBAGD_OBJ_ROOT "/resolution/%/%",
ratbagd_device_get_name(device),
index_buffer);
if (r >= 0) {
r = sd_bus_add_fallback_vtable(bus,
&profile->resolution_vtable_slot,
prefix,
RATBAGD_NAME_ROOT ".Resolution",
ratbagd_resolution_vtable,
ratbagd_profile_find_resolution,
profile);
if (r >= 0)
r = sd_bus_add_node_enumerator(bus,
&profile->resolution_enum_slot,
prefix,
ratbagd_profile_list_resolutions,
profile);
}
if (r < 0) {
errno = -r;
log_error("Cannot register resolutions for '%s': %m\n",
ratbagd_device_get_name(device));
}
return 0;
}
static int ratbagd_profile_list_buttons(sd_bus *bus,
const char *path,
void *userdata,
char ***paths,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_button *button;
char **buttons;
unsigned int i;
buttons = zalloc((profile->n_buttons + 1) * sizeof(char *));
for (i = 0; i < profile->n_buttons; ++i) {
button = profile->buttons[i];
if (!button)
continue;
buttons[i] = strdup_safe(ratbagd_button_get_path(button));
}
buttons[i] = NULL;
*paths = buttons;
return 1;
}
int ratbagd_profile_register_buttons(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile)
{
_cleanup_(freep) char *prefix = NULL;
char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
sprintf(index_buffer, "p%u", profile->index);
/* register button interfaces */
r = sd_bus_path_encode_many(&prefix,
RATBAGD_OBJ_ROOT "/button/%/%",
ratbagd_device_get_name(device),
index_buffer);
if (r >= 0) {
r = sd_bus_add_fallback_vtable(bus,
&profile->button_vtable_slot,
prefix,
RATBAGD_NAME_ROOT ".Button",
ratbagd_button_vtable,
ratbagd_profile_find_button,
profile);
if (r >= 0)
r = sd_bus_add_node_enumerator(bus,
&profile->button_enum_slot,
prefix,
ratbagd_profile_list_buttons,
profile);
}
if (r < 0) {
errno = -r;
log_error("Cannot register buttons for '%s': %m\n",
ratbagd_device_get_name(device));
}
return 0;
}
static int ratbagd_profile_list_leds(sd_bus *bus,
const char *path,
void *userdata,
char ***paths,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbagd_led *led;
char **leds;
unsigned int i;
leds = zalloc((profile->n_leds + 1) * sizeof(char *));
for (i = 0; i < profile->n_leds; ++i) {
led = profile->leds[i];
if (!led)
continue;
leds[i] = strdup_safe(ratbagd_led_get_path(led));
}
leds[i] = NULL;
*paths = leds;
return 1;
}
int ratbagd_profile_register_leds(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile)
{
_cleanup_(freep) char *prefix = NULL;
char index_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
sprintf(index_buffer, "p%u", profile->index);
/* register led interfaces */
r = sd_bus_path_encode_many(&prefix,
RATBAGD_OBJ_ROOT "/led/%/%",
ratbagd_device_get_name(device),
index_buffer);
if (r >= 0) {
r = sd_bus_add_fallback_vtable(bus,
&profile->led_vtable_slot,
prefix,
RATBAGD_NAME_ROOT ".Led",
ratbagd_led_vtable,
ratbagd_profile_find_led,
profile);
if (r >= 0)
r = sd_bus_add_node_enumerator(bus,
&profile->led_enum_slot,
prefix,
ratbagd_profile_list_leds,
profile);
}
if (r < 0) {
errno = -r;
log_error("Cannot register leds for '%s': %m\n",
ratbagd_device_get_name(device));
}
return 0;
}
int ratbagd_for_each_resolution_signal(sd_bus *bus,
struct ratbagd_profile *profile,
int (*func)(sd_bus *bus,
struct ratbagd_resolution *resolution))
{
int rc = 0;
for (size_t i = 0; rc == 0 && i < profile->n_resolutions; i++)
rc = func(bus, profile->resolutions[i]);
return rc;
}

View File

@@ -0,0 +1,418 @@
/***
This file is part of ratbagd.
Copyright 2016 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "ratbagd.h"
#include "shared-macro.h"
#include "libratbag-util.h"
struct ratbagd_resolution {
struct ratbagd_profile *profile;
struct ratbag_resolution *lib_resolution;
unsigned int index;
char *path;
};
static int
ratbagd_resolution_set_report_rate(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
unsigned int rate;
int r;
r = sd_bus_message_read(m, "u", &rate);
if (r < 0)
return r;
/* basic sanity check */
if (rate > 5000 || rate % 100)
return 0;
r = ratbag_resolution_set_report_rate(resolution->lib_resolution,
rate);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"ReportRate",
NULL);
}
return r;
}
static int ratbagd_resolution_active_signal_cb(sd_bus *bus,
struct ratbagd_resolution *resolution)
{
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
/* FIXME: we should cache is_active and only send the signal for
* those resolutions where it changed */
(void) sd_bus_emit_signal(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"IsActive",
"b",
ratbag_resolution_is_active(lib_resolution));
(void) sd_bus_emit_properties_changed(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"IsActive",
NULL);
return 0;
}
static int ratbagd_resolution_set_active(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
int r;
r = ratbag_resolution_set_active(resolution->lib_resolution);
if (r < 0)
return r;
ratbagd_for_each_resolution_signal(sd_bus_message_get_bus(m),
resolution->profile,
ratbagd_resolution_active_signal_cb);
return sd_bus_reply_method_return(m, "u", r);
}
static int ratbagd_resolution_default_signal_cb(sd_bus *bus,
struct ratbagd_resolution *resolution)
{
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
/* FIXME: we should cache is default and only send the signal for
* those resolutions where it changed */
(void) sd_bus_emit_signal(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"IsDefault",
"b",
ratbag_resolution_is_default(lib_resolution));
(void) sd_bus_emit_properties_changed(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"IsDefault",
NULL);
return 0;
}
static int ratbagd_resolution_set_default(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
int r;
r = ratbag_resolution_set_default(resolution->lib_resolution);
if (r < 0)
return r;
ratbagd_for_each_resolution_signal(sd_bus_message_get_bus(m),
resolution->profile,
ratbagd_resolution_default_signal_cb);
return sd_bus_reply_method_return(m, "u", r);
}
static int
ratbagd_resolution_get_capabilities(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
enum ratbag_device_capability cap;
int r;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
cap = RATBAG_RESOLUTION_CAP_INDIVIDUAL_REPORT_RATE;
if (ratbag_resolution_has_capability(lib_resolution, cap)) {
r = sd_bus_message_append(reply, "u", cap);
if (r < 0)
return r;
}
cap = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION;
if (ratbag_resolution_has_capability(lib_resolution, cap)) {
r = sd_bus_message_append(reply, "u", cap);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int
ratbagd_resolution_is_active(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
bool is_active;
is_active = !!ratbag_resolution_is_active(lib_resolution);
return sd_bus_message_append(reply, "b", is_active);
}
static int
ratbagd_resolution_is_default(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
bool is_default;
is_default = !!ratbag_resolution_is_default(lib_resolution);
return sd_bus_message_append(reply, "b", is_default);
}
static int
ratbagd_resolution_get_resolution(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int xres, yres;
xres = ratbag_resolution_get_dpi_x(lib_resolution);
yres = ratbag_resolution_get_dpi_y(lib_resolution);
return sd_bus_message_append(reply, "(uu)", xres, yres);
}
static int
ratbagd_resolution_set_resolution(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
const enum ratbag_device_capability cap = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION;
int xres, yres;
int r;
r = sd_bus_message_read(m, "(uu)", &xres, &yres);
if (r < 0)
return r;
if (!ratbag_resolution_has_capability(lib_resolution, cap)) {
r = ratbag_resolution_set_dpi(resolution->lib_resolution, xres);
} else {
r = ratbag_resolution_set_dpi_xy(resolution->lib_resolution,
xres, yres);
}
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
resolution->path,
RATBAGD_NAME_ROOT ".Resolution",
"Resolution",
NULL);
}
return r;
}
static int
ratbagd_resolution_get_rate(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int rate;
rate = ratbag_resolution_get_report_rate(lib_resolution);
return sd_bus_message_append(reply, "u", rate);
}
static int
ratbagd_resolution_get_minimum(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int min;
min = ratbag_resolution_get_dpi_minimum(lib_resolution);
return sd_bus_message_append(reply, "u", min);
}
static int
ratbagd_resolution_get_maximum(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int max;
max = ratbag_resolution_get_dpi_maximum(lib_resolution);
return sd_bus_message_append(reply, "u", max);
}
const sd_bus_vtable ratbagd_resolution_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Index", "u", NULL, offsetof(struct ratbagd_resolution, index), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Capabilities", "au", ratbagd_resolution_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IsActive", "b", ratbagd_resolution_is_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IsDefault", "b", ratbagd_resolution_is_default, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("Resolution", "(uu)",
ratbagd_resolution_get_resolution,
ratbagd_resolution_set_resolution, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("ReportRate", "u",
ratbagd_resolution_get_rate,
ratbagd_resolution_set_report_rate, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Maximum", "u", ratbagd_resolution_get_maximum, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Minimum", "u", ratbagd_resolution_get_minimum, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("SetActive", "", "u", ratbagd_resolution_set_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDefault", "", "u", ratbagd_resolution_set_default, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
int ratbagd_resolution_new(struct ratbagd_resolution **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_resolution *lib_resolution,
unsigned int index)
{
_cleanup_(ratbagd_resolution_freep) struct ratbagd_resolution *resolution = NULL;
char profile_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1],
resolution_buffer[DECIMAL_TOKEN_MAX(unsigned int) + 1];
int r;
assert(out);
assert(lib_resolution);
resolution = calloc(1, sizeof(*resolution));
if (!resolution)
return -ENOMEM;
resolution->profile = profile;
resolution->lib_resolution = lib_resolution;
resolution->index = index;
sprintf(profile_buffer, "p%u", ratbagd_profile_get_index(profile));
sprintf(resolution_buffer, "r%u", index);
r = sd_bus_path_encode_many(&resolution->path,
RATBAGD_OBJ_ROOT "/resolution/%/%/%",
ratbagd_device_get_name(device),
profile_buffer,
resolution_buffer);
if (r < 0)
return r;
*out = resolution;
resolution = NULL;
return 0;
}
const char *ratbagd_resolution_get_path(struct ratbagd_resolution *resolution)
{
assert(resolution);
return resolution->path;
}
struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *resolution)
{
if (!resolution)
return NULL;
resolution->path = mfree(resolution->path);
resolution->lib_resolution = ratbag_resolution_unref(resolution->lib_resolution);
return mfree(resolution);
}

19
ratbagd/ratbagd.8 Normal file
View File

@@ -0,0 +1,19 @@
.TH ratbagd 8 "Apr 13, 2016" ratbagd
.SH NAME
ratbagd \- system daemon to introspect and modify configurable mice
.SH SYNOPSIS
.B ratbagd
.RB [ \-\-verbose ]
.SH DESCRIPTION
.B ratbagd
starts the daemon. It shouldn't be invoked directly;
.B ratbagd
is normally started through DBus activation.
.SH SEE ALSO
.BR ratbagctl (1)
.SH AUTHORS
.B ratbagd
was written by David Herrmann, Peter Hutterer and Benjamin Tissoires.
.PP
This manual page was written by Stephen Kitt <skitt@debian.org> for
the Debian GNU/Linux system (but may be used by others).

738
ratbagd/ratbagd.c Normal file
View File

@@ -0,0 +1,738 @@
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <linux/input-event-codes.h>
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "ratbagd.h"
#include "shared-macro.h"
#include "libratbag-util.h"
static bool verbose = false;
static const char *SVG_THEMES[] = {
"default",
"gnome",
NULL
};
void log_verbose(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (verbose)
vprintf(fmt, args);
va_end(args);
}
void log_error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s error: ", program_invocation_short_name);
vfprintf(stderr, fmt, args);
va_end(args);
}
static int ratbagd_find_device(sd_bus *bus,
const char *path,
const char *interface,
void *userdata,
void **found,
sd_bus_error *error)
{
_cleanup_(freep) char *name = NULL;
struct ratbagd *ctx = userdata;
struct ratbagd_device *device;
int r;
r = sd_bus_path_decode_many(path,
RATBAGD_OBJ_ROOT "/device/%",
&name);
if (r <= 0)
return r;
device = ratbagd_device_lookup(ctx, name);
if (!device)
return 0;
*found = device;
return 1;
}
static int ratbagd_list_devices(sd_bus *bus,
const char *path,
void *userdata,
char ***paths,
sd_bus_error *error)
{
struct ratbagd *ctx = userdata;
struct ratbagd_device *device;
char **devices, **pos;
devices = calloc(ctx->n_devices + 1, sizeof(char *));
if (!devices)
return -ENOMEM;
pos = devices;
RATBAGD_DEVICE_FOREACH(device, ctx) {
*pos = strdup(ratbagd_device_get_path(device));
if (!*pos)
goto error;
++pos;
}
*pos = NULL;
*paths = devices;
return 1;
error:
for (pos = devices; *pos; ++pos)
free(*pos);
free(devices);
return -ENOMEM;
}
static int ratbagd_get_devices(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd *ctx = userdata;
struct ratbagd_device *device;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
RATBAGD_DEVICE_FOREACH(device, ctx) {
r = sd_bus_message_append(reply,
"o",
ratbagd_device_get_path(device));
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int ratbagd_get_themes(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd *ctx = userdata;
const char **theme;
int r;
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
theme = ctx->themes;
while(*theme) {
r = sd_bus_message_append(reply,
"s",
*theme);
if (r < 0)
return r;
theme++;
}
return sd_bus_message_close_container(reply);
}
#ifdef RATBAG_DEVELOPER_EDITION
#include "libratbag-test.h"
/* A pre-setup sane device. Use for sanity testing by toggling the various
* error conditions.
*/
static const struct ratbag_test_device ratbagd_test_device_descr = {
.num_profiles = 4,
.num_resolutions = 3,
.num_buttons = 4,
.num_leds = 3,
.svg = "logitech-g500.svg",
.profiles = {
{
.buttons = {
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
.action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
.button = 0 },
{ .button_type = RATBAG_BUTTON_TYPE_MIDDLE,
.action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
.key = KEY_3 },
{ .button_type = RATBAG_BUTTON_TYPE_RIGHT,
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
.macro = {
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
.value = KEY_B },
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
.value = KEY_B },
{ .type = RATBAG_MACRO_EVENT_WAIT,
.value = 300 },
},
}
},
.resolutions = {
{ .xres = 100, .yres = 200, .hz = 1000 },
{ .xres = 200, .yres = 300, .hz = 1000, .active = true, .dflt = true },
{ .xres = 300, .yres = 400, .hz = 1000 },
},
.active = true,
.dflt = false,
.leds = {
{
.mode = RATBAG_LED_OFF,
.color = { .red = 255, .green = 0, .blue = 0 },
.hz = 1,
.brightness = 20
},
{
.mode = RATBAG_LED_ON,
.color = { .red = 255, .green = 0, .blue = 0 },
.hz = 1,
.brightness = 20
},
{
.mode = RATBAG_LED_CYCLE,
.color = { .red = 255, .green = 255, .blue = 0 },
.hz = 3,
.brightness = 40
}
},
},
{
.buttons = {
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
.key = 4 },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
.key = 5 },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
.key = 6 },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_KEY,
.key = 7 },
},
.resolutions = {
{ .xres = 1100, .yres = 1200, .hz = 2000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
{ .xres = 1200, .yres = 1300, .hz = 2000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
{ .xres = 1300, .yres = 1400, .hz = 2000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
},
.active = false,
.dflt = true,
},
{
.buttons = {
{ .button_type = RATBAG_BUTTON_TYPE_LEFT,
.action_type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL,
.special = RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO,
.macro = {
{ .type = RATBAG_MACRO_EVENT_KEY_PRESSED,
.value = KEY_A },
{ .type = RATBAG_MACRO_EVENT_KEY_RELEASED,
.value = KEY_A },
{ .type = RATBAG_MACRO_EVENT_WAIT,
.value = 150 },
}
},
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
.button = 2 },
{ .action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON,
.button = 3 },
},
.resolutions = {
{ .xres = 2100, .yres = 2200, .hz = 3000, .active = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
{ .xres = 2200, .yres = 2300, .hz = 3000, .dflt = true, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
{ .xres = 2300, .yres = 2400, .hz = 3000, .caps = RATBAG_RESOLUTION_CAP_SEPARATE_XY_RESOLUTION },
},
.leds = {
{
.mode = RATBAG_LED_ON,
.color = { .red = 255, .green = 0, .blue = 0 },
.hz = 1,
.brightness = 20
},
{
.mode = RATBAG_LED_CYCLE,
.color = { .red = 255, .green = 255, .blue = 0 },
.hz = 3,
.brightness = 40
}
},
.active = false,
.dflt = false,
},
{
.disabled = true,
},
},
.destroyed = NULL,
.destroyed_data = NULL,
};
static int ratbagd_reset_test_device(sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
static struct ratbagd_device *ratbagd_test_device = NULL;
struct ratbagd *ctx = userdata;
struct ratbag_device *device;
int r;
if (ratbagd_test_device) {
ratbagd_device_unlink(ratbagd_test_device);
ratbagd_device_free(ratbagd_test_device);
(void) sd_bus_emit_properties_changed(ctx->bus,
RATBAGD_OBJ_ROOT,
RATBAGD_NAME_ROOT ".Manager",
"Devices",
NULL);
}
device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr);
r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device);
/* the ratbagd_device takes its own reference, drop ours */
ratbag_device_unref(device);
if (r < 0) {
log_error("Cannot track test device\n");
return r;
}
ratbagd_device_link(ratbagd_test_device);
if (m) {
sd_bus_reply_method_return(m, "u", r);
(void) sd_bus_emit_properties_changed(ctx->bus,
RATBAGD_OBJ_ROOT,
RATBAGD_NAME_ROOT ".Manager",
"Devices",
NULL);
}
return 0;
}
static void ratbagd_init_test_device(struct ratbagd *ctx)
{
setenv("RATBAG_TEST", "1", 0);
ratbagd_reset_test_device(NULL, ctx, NULL);
}
#else /* RATBAG_DEVELOPER_EDITION */
static inline void ratbagd_init_test_device(struct ratbagd *ctx) {}
#endif /* RATBAG_DEVELOPER_EDITION */
static const sd_bus_vtable ratbagd_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Devices", "ao", ratbagd_get_devices, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Themes", "as", ratbagd_get_themes, 0, 0),
#ifdef RATBAG_DEVELOPER_EDITION
SD_BUS_METHOD("ResetTestDevice", "", "u", ratbagd_reset_test_device, SD_BUS_VTABLE_UNPRIVILEGED),
#endif /* RATBAG_DEVELOPER_EDITION */
SD_BUS_VTABLE_END,
};
static void ratbagd_process_device(struct ratbagd *ctx,
struct udev_device *udevice)
{
struct ratbag_device *lib_device;
struct ratbagd_device *device;
const char *name;
int r;
/*
* TODO: libratbag should provide some mechanism to allow
* device-grouping, just like libinput does. If multiple input
* devices belong to the same virtual device, we should not add
* it multiple times. Instead, libratbag should group them and
* provide *us* a unique name that identifies the group, rather
* than taking a random input-device as tag.
*/
name = udev_device_get_sysname(udevice);
if (!name || !startswith(name, "event"))
return;
device = ratbagd_device_lookup(ctx, name);
if (streq_ptr("remove", udev_device_get_action(udevice))) {
/* device was removed, unlink it and destroy our context */
if (device) {
ratbagd_device_unlink(device);
ratbagd_device_free(device);
(void) sd_bus_emit_properties_changed(ctx->bus,
RATBAGD_OBJ_ROOT,
RATBAGD_NAME_ROOT ".Manager",
"Devices",
NULL);
}
} else if (device) {
/* device already known, refresh our view of the device */
} else {
enum ratbag_error_code error;
/* device unknown, create new one and link it */
error = ratbag_device_new_from_udev_device(ctx->lib_ctx,
udevice,
&lib_device);
if (error != RATBAG_SUCCESS)
return; /* unsupported device */
r = ratbagd_device_new(&device, ctx, name, lib_device);
/* the ratbagd_device takes its own reference, drop ours */
ratbag_device_unref(lib_device);
if (r < 0) {
log_error("Cannot track device '%s'\n", name);
return;
}
ratbagd_device_link(device);
(void) sd_bus_emit_properties_changed(ctx->bus,
RATBAGD_OBJ_ROOT,
RATBAGD_NAME_ROOT ".Manager",
"Devices",
NULL);
}
}
static int ratbagd_monitor_event(sd_event_source *source,
int fd,
uint32_t mask,
void *userdata)
{
struct ratbagd *ctx = userdata;
struct udev_device *udevice;
udevice = udev_monitor_receive_device(ctx->monitor);
if (!udevice)
return 0;
ratbagd_process_device(ctx, udevice);
udev_device_unref(udevice);
return 0;
}
static int ratbagd_lib_open_restricted(const char *path,
int flags,
void *userdata)
{
return open(path, flags, 0);
}
static void ratbagd_lib_close_restricted(int fd, void *userdata)
{
safe_close(fd);
}
static const struct ratbag_interface ratbagd_lib_interface = {
.open_restricted = ratbagd_lib_open_restricted,
.close_restricted = ratbagd_lib_close_restricted,
};
static struct ratbagd *ratbagd_free(struct ratbagd *ctx)
{
struct ratbagd_device *device;
if (!ctx)
return NULL;
RATBAGD_DEVICE_FOREACH(device, ctx)
ratbagd_device_unlink(device);
ctx->bus = sd_bus_flush_close_unref(ctx->bus);
ctx->monitor_source = sd_event_source_unref(ctx->monitor_source);
ctx->monitor = udev_monitor_unref(ctx->monitor);
ctx->lib_ctx = ratbag_unref(ctx->lib_ctx);
ctx->event = sd_event_unref(ctx->event);
assert(!ctx->device_map.root);
assert(!ctx->lib_ctx); /* ratbag returns non-NULL if still pinned */
return mfree(ctx);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd *, ratbagd_free);
static int ratbagd_init_monitor(struct ratbagd *ctx)
{
struct udev *udev;
int r;
udev = udev_new();
if (!udev)
return -ENOMEM;
ctx->monitor = udev_monitor_new_from_netlink(udev, "udev");
/* we don't need the context to stay around; drop it */
udev_unref(udev);
if (!ctx->monitor)
return -ENOMEM;
r = udev_monitor_filter_add_match_subsystem_devtype(ctx->monitor,
"input",
NULL);
if (r < 0)
return r;
r = udev_monitor_enable_receiving(ctx->monitor);
if (r < 0)
return r;
r = sd_event_add_io(ctx->event,
&ctx->monitor_source,
udev_monitor_get_fd(ctx->monitor),
EPOLLIN,
ratbagd_monitor_event,
ctx);
if (r < 0)
return r;
return 0;
}
static int ratbagd_new(struct ratbagd **out)
{
_cleanup_(ratbagd_freep) struct ratbagd *ctx = NULL;
int r;
ctx = zalloc(sizeof(*ctx));
ctx->themes = SVG_THEMES;
r = sd_event_default(&ctx->event);
if (r < 0)
return r;
r = sd_event_set_watchdog(ctx->event, true);
if (r < 0)
return r;
ctx->lib_ctx = ratbag_create_context(&ratbagd_lib_interface, ctx);
if (!ctx->lib_ctx)
return -ENOMEM;
if (verbose)
ratbag_log_set_priority(ctx->lib_ctx,
RATBAG_LOG_PRIORITY_DEBUG);
r = ratbagd_init_monitor(ctx);
if (r < 0)
return r;
r = sd_bus_open_system(&ctx->bus);
if (r < 0)
return r;
r = sd_bus_add_object_vtable(ctx->bus,
NULL,
RATBAGD_OBJ_ROOT,
RATBAGD_NAME_ROOT ".Manager",
ratbagd_vtable,
ctx);
if (r < 0)
return r;
r = sd_bus_add_fallback_vtable(ctx->bus,
NULL,
RATBAGD_OBJ_ROOT "/device",
RATBAGD_NAME_ROOT ".Device",
ratbagd_device_vtable,
ratbagd_find_device,
ctx);
if (r < 0)
return r;
r = sd_bus_add_node_enumerator(ctx->bus,
NULL,
RATBAGD_OBJ_ROOT "/device",
ratbagd_list_devices,
ctx);
if (r < 0)
return r;
r = sd_bus_request_name(ctx->bus, RATBAGD_NAME_ROOT, 0);
if (r < 0)
return r;
r = sd_bus_attach_event(ctx->bus, ctx->event, 0);
if (r < 0)
return r;
*out = ctx;
ctx = NULL;
return 0;
}
static int ratbagd_run_enumerate(struct ratbagd *ctx)
{
struct udev_list_entry *list, *iter;
struct udev_enumerate *e;
struct udev *udev;
int r;
udev = udev_monitor_get_udev(ctx->monitor);
e = udev_enumerate_new(udev);
if (!e)
return -ENOMEM;
r = udev_enumerate_add_match_subsystem(e, "input");
if (r < 0)
goto exit;
r = udev_enumerate_add_match_is_initialized(e);
if (r < 0)
goto exit;
r = udev_enumerate_scan_devices(e);
if (r < 0)
goto exit;
list = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(iter, list) {
struct udev_device *udevice;
const char *p;
p = udev_list_entry_get_name(iter);
udevice = udev_device_new_from_syspath(udev, p);
if (udevice)
ratbagd_process_device(ctx, udevice);
udev_device_unref(udevice);
}
r = 0;
exit:
udev_enumerate_unref(e);
return r;
}
static int sighandler(sd_event_source *source,
const struct signalfd_siginfo *si,
void *userdata)
{
sd_event *event = sd_event_source_get_event(source);
sd_event_exit(event, 0);
return 0;
}
static int ratbagd_run(struct ratbagd *ctx)
{
int r;
/*
* TODO: We should support exit-on-idle and bus-activation. Note that
* we don't store any state on our own, hence, all we have to do
* is to make sure we advertise device add/remove events via the
* bus (in case there is a listener).
* To track such events, we should store devices we already
* advertised in /run/ratbagd/devices/ and read it out on
* activation.
* Note that this feature requires udev-activation, which might
* not be possible, yet.
*/
r = ratbagd_run_enumerate(ctx);
if (r < 0)
return r;
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_BLOCK, &sigset, NULL);
sd_event_add_signal(ctx->event, NULL, SIGINT, sighandler, NULL);
return sd_event_loop(ctx->event);
}
int main(int argc, char *argv[])
{
struct ratbagd *ctx = NULL;
int r;
if (argc > 1) {
if (streq(argv[1], "--verbose")) {
verbose = true;
} else {
fprintf(stderr, "Usage: %s [--verbose]\n",
program_invocation_short_name);
r = -EINVAL;
goto exit;
}
}
r = ratbagd_new(&ctx);
if (r < 0)
goto exit;
ratbagd_init_test_device(ctx);
r = ratbagd_run(ctx);
exit:
ratbagd_free(ctx);
if (r < 0) {
errno = -r;
log_error("Failed to start ratbagd: %m\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

187
ratbagd/ratbagd.h Normal file
View File

@@ -0,0 +1,187 @@
#pragma once
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <libratbag.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "shared-macro.h"
#include "shared-rbtree.h"
#ifndef RATBAG_DBUS_INTERFACE
#define RATBAG_DBUS_INTERFACE "ratbag1"
#else
#define RATBAG_DEVELOPER_EDITION
#endif
#define RATBAGD_OBJ_ROOT "/org/freedesktop/" RATBAG_DBUS_INTERFACE
#define RATBAGD_NAME_ROOT "org.freedesktop." RATBAG_DBUS_INTERFACE
struct ratbagd;
struct ratbagd_device;
struct ratbagd_profile;
struct ratbagd_resolution;
struct ratbagd_button;
struct ratbagd_led;
void log_verbose(const char *fmt, ...) _printf_(1, 2);
void log_error(const char *fmt, ...) _printf_(1, 2);
/*
* Profiles
*/
extern const sd_bus_vtable ratbagd_profile_vtable[];
int ratbagd_profile_new(struct ratbagd_profile **out,
struct ratbagd_device *device,
struct ratbag_profile *lib_profile,
unsigned int index);
struct ratbagd_profile *ratbagd_profile_free(struct ratbagd_profile *profile);
const char *ratbagd_profile_get_path(struct ratbagd_profile *profile);
bool ratbagd_profile_is_default(struct ratbagd_profile *profile);
unsigned int ratbagd_profile_get_index(struct ratbagd_profile *profile);
int ratbagd_profile_register_resolutions(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile);
int ratbagd_profile_register_buttons(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile);
int ratbagd_profile_register_leds(struct sd_bus *bus,
struct ratbagd_device *device,
struct ratbagd_profile *profile);
int ratbagd_for_each_profile_signal(sd_bus *bus,
struct ratbagd_device *device,
int (*func)(sd_bus *bus,
struct ratbagd_profile *profile));
int ratbagd_for_each_resolution_signal(sd_bus *bus,
struct ratbagd_profile *profile,
int (*func)(sd_bus *bus,
struct ratbagd_resolution *resolution));
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_profile *, ratbagd_profile_free);
/*
* Resolutions
*/
extern const sd_bus_vtable ratbagd_resolution_vtable[];
int ratbagd_resolution_new(struct ratbagd_resolution **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_resolution *lib_resolution,
unsigned int index);
struct ratbagd_resolution *ratbagd_resolution_free(struct ratbagd_resolution *resolution);
const char *ratbagd_resolution_get_path(struct ratbagd_resolution *resolution);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_resolution *, ratbagd_resolution_free);
/*
* Buttons
*/
extern const sd_bus_vtable ratbagd_button_vtable[];
int ratbagd_button_new(struct ratbagd_button **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_button *lib_button,
unsigned int index);
struct ratbagd_button *ratbagd_button_free(struct ratbagd_button *button);
const char *ratbagd_button_get_path(struct ratbagd_button *button);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_button *, ratbagd_button_free);
/*
* Leds
*/
extern const sd_bus_vtable ratbagd_led_vtable[];
int ratbagd_led_new(struct ratbagd_led **out,
struct ratbagd_device *device,
struct ratbagd_profile *profile,
struct ratbag_led *lib_led,
unsigned int index);
struct ratbagd_led *ratbagd_led_free(struct ratbagd_led *led);
const char *ratbagd_led_get_path(struct ratbagd_led *led);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_led *, ratbagd_led_free);
/*
* Devices
*/
extern const sd_bus_vtable ratbagd_device_vtable[];
int ratbagd_device_new(struct ratbagd_device **out,
struct ratbagd *ctx,
const char *name,
struct ratbag_device *lib_device);
struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device);
const char *ratbagd_device_get_name(struct ratbagd_device *device);
const char *ratbagd_device_get_path(struct ratbagd_device *device);
unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device);
unsigned int ratbagd_device_get_num_leds(struct ratbagd_device *device);
bool ratbagd_device_linked(struct ratbagd_device *device);
void ratbagd_device_link(struct ratbagd_device *device);
void ratbagd_device_unlink(struct ratbagd_device *device);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ratbagd_device *, ratbagd_device_free);
struct ratbagd_device *ratbagd_device_lookup(struct ratbagd *ctx,
const char *name);
struct ratbagd_device *ratbagd_device_first(struct ratbagd *ctx);
struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device);
#define RATBAGD_DEVICE_FOREACH(_device, _ctx) \
for ((_device) = ratbagd_device_first(_ctx); \
(_device); \
(_device) = ratbagd_device_next(_device))
/*
* Context
*/
struct ratbagd {
sd_event *event;
struct ratbag *lib_ctx;
struct udev_monitor *monitor;
sd_event_source *monitor_source;
sd_bus *bus;
RBTree device_map;
size_t n_devices;
const char **themes; /* NULL-terminated */
};

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Daemon to introspect and modify configurable mice
[Service]
Type=dbus
BusName=org.freedesktop.ratbag1
ExecStart=@bindir@/ratbagd
Restart=on-abort
[Install]
Alias=dbus-org.freedesktop.ratbag1.service

View File

@@ -1,25 +0,0 @@
# This is the build script used for
# https://semaphoreci.com/libratbag/libratbag/
#
# semaphore uses this script directly, use the following two commands as
# semaphore's build script:
# curl https://raw.githubusercontent.com/libratbag/libratbag/master/semaphore/semaphore-build-script.sh > build-script.sh
# sh ./build-script.sh
sudo apt-get update
sudo apt-get install -y valgrind check libevdev-dev libudev-dev doxygen graphviz
# no meson on 14.04
sudo apt-get install -y python3-pip
sudo pip3 install meson
# ninja on 14.04 is too old
git clone git://github.com/ninja-build/ninja.git
cd ninja
git checkout release
./configure.py --bootstrap
sudo cp ninja /usr/bin/ninja
cd ..
meson builddir
ninja -C builddir test

View File

@@ -652,6 +652,9 @@ etekcity_probe(struct ratbag_device *device)
rc = ratbag_hidraw_raw_request(device, ETEKCITY_REPORT_ID_SPEED_SETTING,
drv_data->speed_setting, ETEKCITY_REPORT_SIZE_SPEED_SETTING,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (rc)
return rc;
log_debug(device->ratbag, "device is at %d ms of latency\n", drv_data->speed_setting[2]);
/* profiles are 0-indexed */
@@ -661,6 +664,7 @@ etekcity_probe(struct ratbag_device *device)
ETEKCITY_BUTTON_MAX + 1,
ETEKCITY_LED);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
active_idx = etekcity_current_profile(device);

View File

@@ -1004,6 +1004,7 @@ gskill_probe(struct ratbag_device *device)
GSKILL_BUTTON_MAX, GSKILL_NUM_LED);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);

View File

@@ -290,27 +290,22 @@ hidpp10drv_read_button(struct ratbag_button *button)
}
static int
hidpp10drv_write_button(struct ratbag_button *button,
hidpp10drv_write_button(struct hidpp10_profile *profile,
struct ratbag_button *button,
const struct ratbag_button_action *action)
{
struct ratbag_device *device = button->profile->device;
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp10_device *hidpp10 = drv_data->dev;
struct hidpp10_profile profile;
uint8_t code;
int ret;
if (hidpp10->profile_type == HIDPP10_PROFILE_UNKNOWN)
return -ENOTSUP;
ret = hidpp10_get_profile(hidpp10, button->profile->index, &profile);
if (ret)
return ret;
switch (action->type) {
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
profile.buttons[button->index].button.type = PROFILE_BUTTON_TYPE_BUTTON;
profile.buttons[button->index].button.button = action->action.button;
profile->buttons[button->index].button.type = PROFILE_BUTTON_TYPE_BUTTON;
profile->buttons[button->index].button.button = action->action.button;
break;
case RATBAG_BUTTON_ACTION_TYPE_KEY:
code = ratbag_hidraw_get_keyboard_usage_from_keycode(device, action->action.key.key);
@@ -319,26 +314,26 @@ hidpp10drv_write_button(struct ratbag_button *button,
if (code == 0)
return -EINVAL;
profile.buttons[button->index].consumer_control.type = PROFILE_BUTTON_TYPE_CONSUMER_CONTROL;
profile.buttons[button->index].consumer_control.consumer_control = code;
profile->buttons[button->index].consumer_control.type = PROFILE_BUTTON_TYPE_CONSUMER_CONTROL;
profile->buttons[button->index].consumer_control.consumer_control = code;
} else {
profile.buttons[button->index].keys.type = PROFILE_BUTTON_TYPE_KEYS;
profile.buttons[button->index].keys.key = code;
profile->buttons[button->index].keys.type = PROFILE_BUTTON_TYPE_KEYS;
profile->buttons[button->index].keys.key = code;
}
break;
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
code = hidpp10_onboard_profiles_get_code_from_special(action->action.special);
if (code == 0)
return -EINVAL;
profile.buttons[button->index].special.type = PROFILE_BUTTON_TYPE_SPECIAL;
profile.buttons[button->index].special.special = code;
profile->buttons[button->index].special.type = PROFILE_BUTTON_TYPE_SPECIAL;
profile->buttons[button->index].special.special = code;
break;
case RATBAG_BUTTON_ACTION_TYPE_MACRO:
default:
return -ENOTSUP;
}
return hidpp10_set_profile(drv_data->dev, button->profile->index, &profile);
return 0;
}
static int
@@ -356,12 +351,12 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
struct ratbag_device *device = profile->device;
struct hidpp10drv_data *drv_data;
struct hidpp10_device *hidpp10;
struct hidpp10_profile p;
struct hidpp10_profile p = {0};
struct ratbag_resolution *res;
int rc;
unsigned int i;
uint16_t xres, yres;
int8_t idx;
uint8_t idx;
drv_data = ratbag_get_drv_data(device);
hidpp10 = drv_data->dev;
@@ -369,6 +364,8 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
if (rc)
return;
profile->is_enabled = p.enabled;
rc = hidpp10_get_current_profile(hidpp10, &idx);
if (rc == 0 && (unsigned int)idx == profile->index)
profile->is_active = true;
@@ -377,7 +374,12 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
if (rc)
xres = 0xffff;
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
for (i = 0; i < profile->resolution.num_modes; i++) {
unsigned int min, max;
res = ratbag_resolution_init(profile, i,
p.dpi_modes[i].xres,
p.dpi_modes[i].yres,
@@ -388,8 +390,15 @@ hidpp10drv_read_profile(struct ratbag_profile *profile, unsigned int index)
res->dpi_x == xres &&
res->dpi_y == yres)
res->is_active = true;
if (i == p.default_dpi_mode)
if (i == p.default_dpi_mode) {
res->is_default = true;
if (!profile->is_active)
res->is_active = true;
}
min = hidpp10_dpi_table_get_min_dpi(hidpp10);
max = hidpp10_dpi_table_get_max_dpi(hidpp10);
ratbag_resolution_set_range(res, min, max);
}
}
@@ -400,22 +409,18 @@ hidpp10drv_write_profile(struct ratbag_profile *profile)
}
static int
hidpp10drv_write_resolution_dpi(struct ratbag_resolution *resolution,
hidpp10drv_write_resolution_dpi(struct hidpp10_profile *p,
struct ratbag_resolution *resolution,
int dpi_x, int dpi_y)
{
struct ratbag_profile *profile = resolution->profile;
struct ratbag_device *device = profile->device;
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp10_device *hidpp10 = drv_data->dev;
struct hidpp10_profile p;
unsigned int index;
uint16_t cur_dpi_x, cur_dpi_y;
int rc;
rc = hidpp10_get_profile(hidpp10, profile->index, &p);
if (rc)
return rc;
/* store the current resolution */
rc = hidpp10_get_current_resolution(hidpp10, &cur_dpi_x, &cur_dpi_y);
if (rc)
@@ -430,13 +435,8 @@ hidpp10drv_write_resolution_dpi(struct ratbag_resolution *resolution,
/* retrieve which resolution is asked to be changed */
index = resolution - profile->resolution.modes;
p.dpi_modes[index].xres = dpi_x;
p.dpi_modes[index].yres = dpi_y;
/* this effectively switches the resolution to the default in the profile */
rc = hidpp10_set_profile(drv_data->dev, profile->index, &p);
if (rc)
return rc;
p->dpi_modes[index].xres = dpi_x;
p->dpi_modes[index].yres = dpi_y;
/* restore the current setting */
return hidpp10_set_current_resolution(hidpp10, cur_dpi_x, cur_dpi_y);
@@ -446,30 +446,32 @@ static int
hidpp10drv_fill_from_profile(struct ratbag_device *device, struct hidpp10_device *dev)
{
int rc;
struct hidpp10_profile profile;
struct hidpp10_directory directory[16];
int count;
count = hidpp10_get_profile_directory(dev, directory, ARRAY_LENGTH(directory));
if (count < 0)
return count;
struct hidpp10_profile profile = {0};
unsigned int i;
/* We don't know the HID++1.0 requests to query for buttons, etc.
* Simply get the first profile and fill the device information in
* from that.
* Simply get the first enabled profile and fill in the device
* information from that.
*/
rc = hidpp10_get_profile(dev, 0, &profile);
if (rc)
return rc;
for (i = 0; i < dev->profile_count; i++) {
rc = hidpp10_get_profile(dev, i, &profile);
if (rc)
return rc;
if (profile.enabled)
break;
}
ratbag_device_init_profiles(device,
count,
dev->profile_count,
profile.num_dpi_modes,
profile.num_buttons,
profile.num_leds);
if (dev->profile_type != HIDPP10_PROFILE_UNKNOWN) {
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
}
@@ -491,6 +493,60 @@ hidpp10_log(void *userdata, enum hidpp_log_priority priority, const char *format
log_msg_va(device->ratbag, priority, format, args);
}
static int
hidpp10drv_commit(struct ratbag_device *device)
{
struct hidpp10drv_data *drv_data = ratbag_get_drv_data(device);
struct hidpp10_device *dev = drv_data->dev;
struct ratbag_profile *profile;
struct ratbag_button *button;
struct ratbag_resolution *resolution;
struct hidpp10_profile p;
int rc;
unsigned int i;
list_for_each(profile, &device->profiles, link) {
if (!profile->dirty)
continue;
rc = hidpp10_get_profile(dev, profile->index, &p);
if (rc)
return rc;
p.enabled = profile->is_enabled;
for (i = 0; i < profile->resolution.num_modes; i++) {
resolution = &profile->resolution.modes[i];
rc = hidpp10drv_write_resolution_dpi(&p,
resolution,
resolution->dpi_x,
resolution->dpi_y);
if (rc)
return RATBAG_ERROR_DEVICE;
}
list_for_each(button, &profile->buttons, link) {
struct ratbag_button_action action = button->action;
if (!button->dirty)
continue;
rc = hidpp10drv_write_button(&p, button, &action);
if (rc)
return RATBAG_ERROR_DEVICE;
}
if (dev->profile_type != HIDPP10_PROFILE_UNKNOWN) {
rc = hidpp10_set_profile(dev, profile->index, &p);
if (rc)
return RATBAG_ERROR_DEVICE;
}
}
return RATBAG_SUCCESS;
}
static int
hidpp10drv_probe(struct ratbag_device *device)
{
@@ -502,6 +558,7 @@ hidpp10drv_probe(struct ratbag_device *device)
const char *prop;
int device_idx = HIDPP_WIRED_DEVICE_IDX;
int nread = 0;
unsigned int profile_count = 1;
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
if (rc)
@@ -519,6 +576,10 @@ hidpp10drv_probe(struct ratbag_device *device)
type = HIDPP10_PROFILE_G700;
else if (strcasecmp("G9", prop) == 0)
type = HIDPP10_PROFILE_G9;
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_PROFILE_COUNT");
if (prop)
profile_count = atoi(prop);
}
prop = ratbag_device_get_udev_property(device, "RATBAG_HIDPP10_INDEX");
@@ -540,7 +601,7 @@ hidpp10drv_probe(struct ratbag_device *device)
* If there is a special need like for G700(s), we can pass a
* udev prop RATBAG_HIDPP10_INDEX.
*/
dev = hidpp10_device_new(&base, device_idx, type);
dev = hidpp10_device_new(&base, device_idx, type, profile_count);
if (!dev) {
log_error(device->ratbag,
@@ -578,6 +639,10 @@ hidpp10drv_probe(struct ratbag_device *device)
device->name);
}
rc = hidpp10_device_read_profiles(dev);
if (rc)
goto err;
drv_data->dev = dev;
ratbag_set_drv_data(device, drv_data);
@@ -626,6 +691,5 @@ struct ratbag_driver hidpp10_driver = {
.write_profile = hidpp10drv_write_profile,
.set_active_profile = hidpp10drv_set_current_profile,
.read_button = hidpp10drv_read_button,
.write_button = hidpp10drv_write_button,
.write_resolution_dpi = hidpp10drv_write_resolution_dpi,
.commit = hidpp10drv_commit,
};

View File

@@ -300,12 +300,12 @@ hidpp20drv_write_button_1b04(struct ratbag_button *button,
if (!mapping)
return -EINVAL;
control->reporting.divert = 1;
control->reporting.divert = 0;
control->reporting.remapped = mapping;
control->reporting.updated = 1;
rc = hidpp20_special_key_mouse_set_control(drv_data->dev, control);
if (rc == ERR_INVALID_ADDRESS)
if (rc == HIDPP20_ERR_INVALID_ARGUMENT)
return -EINVAL;
if (rc)
@@ -527,10 +527,17 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
rc = hidpp20drv_read_resolution_dpi_2201(device);
if (rc < 0)
return rc;
for (i = 0; i < profile->resolution.num_modes; i++) {
int dpi = drv_data->sensors[i].dpi;
struct hidpp20_sensor *sensor;
/* We only look at the first sensor. Multiple
* sensors is too niche to care about right now */
sensor = &drv_data->sensors[0];
/* FIXME: retrieve the refresh rate */
res = ratbag_resolution_init(profile, i, dpi, dpi, 0);
res = ratbag_resolution_init(profile, i, sensor->dpi, sensor->dpi, 0);
ratbag_resolution_set_range(res, sensor->dpi_min, sensor->dpi_max);
/* FIXME: we mark all resolutions as active because
* they are from different sensors */
@@ -699,7 +706,10 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct ratbag_resolution *res;
struct hidpp20_profile *p;
unsigned i, dpi = 0;
unsigned int i;
int dpi_index = 0xff;
profile->is_enabled = drv_data->profiles->profiles[index].enabled;
hidpp20drv_read_onboard_profile(device, profile->index);
@@ -707,25 +717,36 @@ hidpp20drv_read_profile_8100(struct ratbag_profile *profile, unsigned int index)
if ((int)index == hidpp20drv_current_profile(device))
profile->is_active = true;
/* retrieve the resolution through 220X as the profile doesn't has it */
if (profile->is_active)
hidpp20drv_read_resolution_dpi(profile);
dpi_index = hidpp20_onboard_profiles_get_current_dpi_index(drv_data->dev);
dpi = ratbag_resolution_get_dpi(profile->resolution.modes);
if (dpi_index < 0)
dpi_index = 0xff;
p = &drv_data->profiles->profiles[index];
for (i = 0; i < profile->resolution.num_modes; i++) {
struct hidpp20_sensor *sensor;
/* We only look at the first sensor. Multiple
* sensors is too niche to care about right now */
sensor = &drv_data->sensors[0];
res = ratbag_resolution_init(profile, i,
p->dpi[i],
p->dpi[i],
p->report_rate);
if (profile->is_active &&
res->dpi_x == dpi)
i == (unsigned int)dpi_index)
res->is_active = true;
if (i == p->default_dpi)
if (i == p->default_dpi) {
res->is_default = true;
if (!profile->is_active || dpi_index < 0 || dpi_index > 4)
res->is_active = true;
}
ratbag_resolution_set_range(res, sensor->dpi_min, sensor->dpi_max);
}
}
@@ -757,6 +778,8 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
&feature_index,
&feature_type,
&feature_version);
if (rc < 0)
return rc;
switch (feature) {
case HIDPP_PAGE_ROOT:
@@ -765,6 +788,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
break;
case HIDPP_PAGE_MOUSE_POINTER_BASIC: {
drv_data->capabilities |= HIDPP_CAP_RESOLUTION_2200;
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
break;
}
case HIDPP_PAGE_ADJUSTABLE_DPI: {
@@ -774,6 +798,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
rc = hidpp20drv_read_resolution_dpi_2201(device);
if (rc < 0)
return 0; /* this is not a hard failure */
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
drv_data->capabilities |= HIDPP_CAP_SWITCHABLE_RESOLUTION_2201;
break;
@@ -781,6 +806,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
case HIDPP_PAGE_SPECIAL_KEYS_BUTTONS: {
log_debug(ratbag, "device has programmable keys/buttons\n");
drv_data->capabilities |= HIDPP_CAP_BUTTON_KEY_1b04;
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
/* we read the profile once to get the correct number of
* supported buttons. */
@@ -833,6 +859,8 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
case HIDPP_PAGE_ONBOARD_PROFILES: {
log_debug(ratbag, "device has onboard profiles\n");
drv_data->capabilities |= HIDPP_CAP_ONBOARD_PROFILES_8100;
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
rc = hidpp20_onboard_profiles_allocate(drv_data->dev, &drv_data->profiles);
if (rc < 0)
@@ -856,7 +884,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
}
static int
hidpp20_commit(struct ratbag_device *device)
hidpp20drv_commit(struct ratbag_device *device)
{
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct ratbag_profile *profile;
@@ -864,14 +892,18 @@ hidpp20_commit(struct ratbag_device *device)
struct ratbag_led *led;
struct ratbag_resolution *resolution;
int rc;
unsigned int i;
unsigned int i, dpi_index = 0;
list_for_each(profile, &device->profiles, link) {
if (!profile->dirty)
continue;
drv_data->profiles->profiles[profile->index].enabled = profile->is_enabled;
for (i = 0; i < profile->resolution.num_modes; i++) {
resolution = &profile->resolution.modes[i];
if (resolution->is_active)
dpi_index = i;
rc = hidpp20drv_update_resolution_dpi(resolution,
resolution->dpi_x,
@@ -900,10 +932,14 @@ hidpp20_commit(struct ratbag_device *device)
return RATBAG_ERROR_DEVICE;
}
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100)
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
hidpp20_onboard_profiles_write(drv_data->dev,
profile->index,
drv_data->profiles);
if (profile->is_active)
hidpp20_onboard_profiles_set_current_dpi_index(drv_data->dev,
dpi_index);
}
}
return RATBAG_SUCCESS;
@@ -954,18 +990,16 @@ static void
hidpp20drv_remove(struct ratbag_device *device)
{
struct hidpp20drv_data *drv_data;
struct hidpp20_device *dev;
if (!device)
return;
drv_data = ratbag_get_drv_data(device);
dev = drv_data->dev;
ratbag_close_hidraw(device);
if (drv_data->profiles)
hidpp20_onboard_profiles_destroy(dev, drv_data->profiles);
hidpp20_onboard_profiles_destroy(drv_data->profiles);
free(drv_data->controls);
free(drv_data->sensors);
if (drv_data->dev)
@@ -1050,7 +1084,7 @@ struct ratbag_driver hidpp20_driver = {
.id = "hidpp20",
.probe = hidpp20drv_probe,
.remove = hidpp20drv_remove,
.commit = hidpp20_commit,
.commit = hidpp20drv_commit,
.read_profile = hidpp20drv_read_profile,
.set_active_profile = hidpp20drv_set_current_profile,
.read_button = hidpp20drv_read_button,

View File

@@ -369,8 +369,11 @@ logitech_g300_probe(struct ratbag_device *device)
LOGITECH_G300_BUTTON_MAX + 1,
LOGITECH_G300_NUM_LED);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
active_idx = logitech_g300_current_profile(device);

View File

@@ -800,6 +800,7 @@ roccat_probe(struct ratbag_device *device)
ROCCAT_BUTTON_MAX + 1,
ROCCAT_LED_MAX);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
active_idx = roccat_current_profile(device);

View File

@@ -35,24 +35,41 @@ test_read_profile(struct ratbag_profile *profile, unsigned int index)
struct ratbag_test_device *d = ratbag_get_drv_data(profile->device);
struct ratbag_test_profile *p;
struct ratbag_test_resolution *r;
struct ratbag_resolution *res;
unsigned int i;
bool active_set = false;
bool default_set = false;
assert(index < d->num_profiles);
p = &d->profiles[index];
for (i = 0; i < d->num_resolutions; i++) {
struct ratbag_resolution *res;
r = &p->resolutions[i];
res = ratbag_resolution_init(profile, i, r->xres, r->yres, r->hz);
res->is_active = r->active;
if (r->active)
active_set = true;
res->is_default = r->dflt;
res->capabilities = r->caps;
if (r->dflt)
default_set = true;
ratbag_resolution_set_cap(res, r->caps);
res->hz = r->hz;
assert(res);
}
/* special case triggered by the test suite when num_resolutions is 0 */
if (d->num_resolutions) {
res = ratbag_profile_get_resolution(profile, 0);
assert(res);
if (!active_set)
res->is_active = true;
if (!default_set)
res->is_default = true;
ratbag_resolution_unref(res);
}
profile->is_active = p->active;
profile->is_enabled = !p->disabled;
}
static int
@@ -80,11 +97,15 @@ test_read_button(struct ratbag_button *button)
struct ratbag_device *device = button->profile->device;
struct ratbag_test_device *d = ratbag_get_drv_data(device);
struct ratbag_test_profile *p = &d->profiles[button->profile->index];
struct ratbag_test_button *b = &p->buttons[button->index];
struct ratbag_button_macro *m;
const char data[] = "TEST";
const char *c;
struct ratbag_test_macro_event *e;
int idx;
switch (p->buttons[button->index].type) {
/* Only take the button types from the first profile */
button->type = d->profiles[0].buttons[button->index].button_type;
switch (b->action_type) {
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
button->action.action.button = p->buttons[button->index].button;
@@ -97,21 +118,19 @@ test_read_button(struct ratbag_button *button)
button->action.type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
m = ratbag_button_macro_new("test macro");
ARRAY_FOR_EACH(data, c) {
char str[6];
snprintf_safe(str, 6, "KEY_%c", *c);
ratbag_button_macro_set_event(m,
0,
RATBAG_MACRO_EVENT_KEY_PRESSED,
libevdev_event_code_from_name(EV_KEY, str));
ratbag_button_macro_set_event(m,
0,
RATBAG_MACRO_EVENT_KEY_RELEASED,
libevdev_event_code_from_name(EV_KEY, str));
idx = 0;
ARRAY_FOR_EACH(b->macro, e) {
if (e->type == RATBAG_MACRO_EVENT_NONE)
break;
ratbag_button_macro_set_event(m, idx++, e->type, e->value);
}
ratbag_button_copy_macro(button, m);
ratbag_button_macro_unref(m);
break;
case RATBAG_BUTTON_ACTION_TYPE_SPECIAL:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL;
button->action.action.special = p->buttons[button->index].special;
break;
default:
button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
}
@@ -170,6 +189,13 @@ test_write_led(struct ratbag_led *led,
return 0;
}
static const char* test_get_svg_name(const struct ratbag_device *device)
{
struct ratbag_test_device *d = ratbag_get_drv_data(device);
return d->svg;
}
static int
test_fake_probe(struct ratbag_device *device)
{
@@ -177,9 +203,12 @@ test_fake_probe(struct ratbag_device *device)
}
static int
test_probe(struct ratbag_device *device, void *data)
test_probe(struct ratbag_device *device, const void *data)
{
struct ratbag_test_device *test_device = data;
struct ratbag_test_device *test_device;
test_device = zalloc(sizeof(*test_device));
memcpy(test_device, data, sizeof(*test_device));
ratbag_set_drv_data(device, test_device);
ratbag_device_init_profiles(device,
@@ -187,8 +216,10 @@ test_probe(struct ratbag_device *device, void *data)
test_device->num_resolutions,
test_device->num_buttons,
test_device->num_leds);
if (test_device->num_profiles > 1)
if (test_device->num_profiles > 1) {
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_DISABLE_PROFILE);
}
return 0;
}
@@ -203,6 +234,7 @@ test_remove(struct ratbag_device *device)
if (d->destroyed)
d->destroyed(device, d->destroyed_data);
ratbag_set_drv_data(device, NULL);
free(d);
}
struct ratbag_driver test_driver = {
@@ -211,6 +243,7 @@ struct ratbag_driver test_driver = {
.probe = test_fake_probe,
.test_probe = test_probe,
.remove = test_remove,
.get_svg_name = test_get_svg_name,
.read_profile = test_read_profile,
.write_profile = test_write_profile,
.set_active_profile = test_set_active_profile,

View File

@@ -36,7 +36,7 @@
#include "libratbag-private.h"
const char *hidpp_errors[0xFF] = {
const char *hidpp10_errors[0x100] = {
[0x00] = "ERR_SUCCESS",
[0x01] = "ERR_INVALID_SUBID",
[0x02] = "ERR_INVALID_ADDRESS",
@@ -50,7 +50,21 @@ const char *hidpp_errors[0xFF] = {
[0x0A] = "ERR_REQUEST_UNAVAILABLE",
[0x0B] = "ERR_INVALID_PARAM_VALUE",
[0x0C] = "ERR_WRONG_PIN_CODE",
[0x0D ... 0xFE] = NULL,
[0x0D ... 0xFF] = NULL,
};
const char *hidpp20_errors[0x100] = {
[0x00] = "ERR_NO_ERROR",
[0x01] = "ERR_UNKNOWN",
[0x02] = "ERR_INVALID_ARGUMENT",
[0x03] = "ERR_OUT_OF_RANGE",
[0x04] = "ERR_HARDWARE_ERROR",
[0x05] = "ERR_LOGITECH_INTERNAL",
[0x06] = "ERR_INVALID_FEATURE_INDEX",
[0x07] = "ERR_INVALID_FUNCTION_ID",
[0x08] = "ERR_BUSY",
[0x09] = "ERR_UNSUPPORTED",
[0x0A ... 0xFF] = NULL,
};
struct hidpp20_1b04_action_mapping {

View File

@@ -51,19 +51,30 @@
#define GET_LONG_REGISTER_RSP 0x83
#define __ERROR_MSG 0x8F
#define ERR_SUCCESS 0x00
#define ERR_INVALID_SUBID 0x01
#define ERR_INVALID_ADDRESS 0x02
#define ERR_INVALID_VALUE 0x03
#define ERR_CONNECT_FAIL 0x04
#define ERR_TOO_MANY_DEVICES 0x05
#define ERR_ALREADY_EXISTS 0x06
#define ERR_BUSY 0x07
#define ERR_UNKNOWN_DEVICE 0x08
#define ERR_RESOURCE_ERROR 0x09
#define ERR_REQUEST_UNAVAILABLE 0x0A
#define ERR_INVALID_PARAM_VALUE 0x0B
#define ERR_WRONG_PIN_CODE 0x0C
#define HIDPP10_ERR_SUCCESS 0x00
#define HIDPP10_ERR_INVALID_SUBID 0x01
#define HIDPP10_ERR_INVALID_ADDRESS 0x02
#define HIDPP10_ERR_INVALID_VALUE 0x03
#define HIDPP10_ERR_CONNECT_FAIL 0x04
#define HIDPP10_ERR_TOO_MANY_DEVICES 0x05
#define HIDPP10_ERR_ALREADY_EXISTS 0x06
#define HIDPP10_ERR_BUSY 0x07
#define HIDPP10_ERR_UNKNOWN_DEVICE 0x08
#define HIDPP10_ERR_RESOURCE_ERROR 0x09
#define HIDPP10_ERR_REQUEST_UNAVAILABLE 0x0A
#define HIDPP10_ERR_INVALID_PARAM_VALUE 0x0B
#define HIDPP10_ERR_WRONG_PIN_CODE 0x0C
#define HIDPP20_ERR_NO_ERROR 0x00
#define HIDPP20_ERR_UNKNOWN 0x01
#define HIDPP20_ERR_INVALID_ARGUMENT 0x02
#define HIDPP20_ERR_OUT_OF_RANGE 0x03
#define HIDPP20_ERR_HARDWARE_ERROR 0x04
#define HIDPP20_ERR_LOGITECH_INTERNAL 0x05
#define HIDPP20_ERR_INVALID_FEATURE_INDEX 0x06
#define HIDPP20_ERR_INVALID_FUNCTION_ID 0x07
#define HIDPP20_ERR_BUSY 0x08
#define HIDPP20_ERR_UNSUPPORTED 0x09
/* Keep this in sync with ratbag_log_priority */
enum hidpp_log_priority {
@@ -97,7 +108,8 @@ hidpp_device_set_log_handler(struct hidpp_device *dev,
enum hidpp_log_priority priority,
void *userdata);
extern const char *hidpp_errors[0xFF];
extern const char *hidpp10_errors[0x100];
extern const char *hidpp20_errors[0x100];
const char *
hidpp20_1b04_get_physical_mapping_name(uint16_t value);

View File

@@ -31,6 +31,7 @@
#include "config.h"
#include <assert.h>
#include <linux/types.h>
#include <errno.h>
#include <stdio.h>
@@ -85,6 +86,32 @@ const char *device_types[0xFF] = {
[0x0A ... 0xFE] = NULL,
};
unsigned int
hidpp10_dpi_table_get_max_dpi(struct hidpp10_device *dev)
{
struct hidpp10_dpi_mapping *dpi;
assert(dev->dpi_count > 0);
/* We assume a sorted list */
dpi = &dev->dpi_table[dev->dpi_count - 1];
return dpi->dpi;
}
unsigned int
hidpp10_dpi_table_get_min_dpi(struct hidpp10_device *dev)
{
struct hidpp10_dpi_mapping *dpi;
assert(dev->dpi_count > 0);
/* We assume a sorted list, index 0 is always 0 */
dpi = &dev->dpi_table[1];
return dpi->dpi;
}
int
hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
const char *str_list)
@@ -136,9 +163,6 @@ hidpp10_build_dpi_table_from_list(struct hidpp10_device *dev,
if (index != count)
goto err;
/* mark the state as invalid */
dev->profile_count = 0;
return 0;
err:
@@ -176,9 +200,6 @@ hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
dev->dpi_table[i].dpi = round((min + step * i) / 25.0f) * 25;
}
/* mark the state as invalid */
dev->profile_count = 0;
return 0;
}
@@ -247,7 +268,7 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
" HID++ error from the %s (%d): %s (%02x)\n",
read_buffer.msg.device_idx == HIDPP_RECEIVER_IDX ? "receiver" : "device",
read_buffer.msg.device_idx,
hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code",
hidpp10_errors[hidpp_err] ? hidpp10_errors[hidpp_err] : "Undocumented error code",
hidpp_err);
break;
}
@@ -693,29 +714,83 @@ hidpp10_get_dpi_value(struct hidpp10_device *dev, uint8_t raw_value)
return 0;
}
int
hidpp10_get_profile_directory(struct hidpp10_device *dev,
struct hidpp10_directory *out,
size_t nelems)
static int
hidpp10_write_profile_directory(struct hidpp10_device *dev)
{
unsigned int i;
unsigned int i, index;
int res;
uint8_t bytes[HIDPP10_PAGE_SIZE] = { 0 };
uint8_t bytes[HIDPP10_PAGE_SIZE];
struct hidpp10_directory *directory = (struct hidpp10_directory *)bytes;
size_t count;
uint16_t crc;
if (dev->profile_type == HIDPP10_PROFILE_UNKNOWN) {
hidpp_log_debug(&dev->base, "no profile type given\n");
return 0;
}
if (dev->profile_directory) {
count = 0;
while (dev->profile_directory[count].page) {
count++;
}
memset(bytes, 0xff, sizeof(bytes));
goto out;
index = 0;
for (i = 0; i < dev->profile_count; i++) {
if (!dev->profiles[i].enabled)
continue;
directory[index].page = dev->profiles[i].page;
directory[index].offset = dev->profiles[i].offset;
directory[index].led_mask = ((0b111 << index) >> 2) & 0b111;
++index;
}
crc = hidpp_crc_ccitt(bytes, HIDPP10_PAGE_SIZE - 2);
hidpp_set_unaligned_be_u16(&bytes[HIDPP10_PAGE_SIZE - 2], crc);
res = hidpp10_send_hot_payload(dev,
0x00, 0x0000, /* destination: RAM */
bytes,
HIDPP10_PAGE_SIZE / 2);
if (res < 0)
return res;
res = hidpp10_erase_memory(dev, 0x01);
if (res < 0)
return res;
res = hidpp10_write_flash(dev,
0x00, 0x0000,
0x01, 0x0000,
HIDPP10_PAGE_SIZE / 2);
if (res < 0)
return res;
res = hidpp10_send_hot_payload(dev,
0x00, 0x0000, /* destination: RAM */
bytes + HIDPP10_PAGE_SIZE / 2,
HIDPP10_PAGE_SIZE / 2);
if (res < 0)
return res;
res = hidpp10_write_flash(dev,
0x00, 0x0000,
0x01, HIDPP10_PAGE_SIZE / 2,
HIDPP10_PAGE_SIZE / 2);
if (res < 0)
return res;
return 0;
}
static int
hidpp10_read_profile_directory(struct hidpp10_device *dev)
{
unsigned int i;
int res;
uint8_t bytes[HIDPP10_PAGE_SIZE] = { 0 };
struct hidpp10_directory *directory = (struct hidpp10_directory *)bytes;
unsigned int count;
if (dev->profile_type == HIDPP10_PROFILE_UNKNOWN) {
hidpp_log_debug(&dev->base, "no profile type given\n");
return 0;
}
hidpp_log_raw(&dev->base, "Fetching the profiles' directory\n");
@@ -725,46 +800,29 @@ hidpp10_get_profile_directory(struct hidpp10_device *dev,
return res;
count = 0;
/* assume 16 profiles max */
for (i = 0; i < 16; i++) {
for (i = 0; i < dev->profile_count; i++) {
if (directory[i].page == 0xFF)
break;
dev->profiles[i].page = directory[i].page;
dev->profiles[i].offset = directory[i].offset;
dev->profiles[i].enabled = true;
count++;
}
dev->profile_directory = zalloc((count + 1) * sizeof(struct hidpp10_directory));
memcpy(dev->profile_directory, directory, count * sizeof(struct hidpp10_directory));
out:
if (dev->profile_count != count) {
if (dev->profiles)
free(dev->profiles);
dev->profiles = zalloc(count * sizeof(struct hidpp10_profile));
dev->profile_count = count;
}
count = min(count, nelems);
memcpy(out, dev->profile_directory, count * sizeof(out[0]));
for (i = count; i < dev->profile_count; i++)
dev->profiles[i].enabled = false;
return count;
}
int
hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile)
{
unsigned idx = dev->index;
union hidpp10_message profile = CMD_PROFILE(idx, GET_REGISTER_REQ);
int res;
unsigned i;
int8_t type, page, offset;
struct hidpp10_directory directory[16]; /* completely random profile count */
int count = 0;
hidpp_log_raw(&dev->base, "Fetching the profiles' directory\n");
count = hidpp10_get_profile_directory(dev, directory,
ARRAY_LENGTH(directory));
if (count < 0)
return count;
uint8_t type, page, offset;
hidpp_log_raw(&dev->base, "Fetching current profile\n");
@@ -779,14 +837,14 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
*current_profile = page;
/* If the profile exceeds the directory length, default to
* the first */
if (*current_profile > count)
if (*current_profile > dev->profile_count)
*current_profile = 0;
return 0;
case PROFILE_TYPE_ADDRESS:
offset = profile.msg.parameters[2];
for (i = 0; i < ARRAY_LENGTH(directory) && directory[i].page < 32; i++) {
if (page == directory[i].page &&
offset == directory[i].offset) {
for (i = 0; i < dev->profile_count; i++) {
if (page == dev->profiles[i].page &&
offset == dev->profiles[i].offset) {
*current_profile = i;
return 0;
}
@@ -806,21 +864,12 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
static int
hidpp10_set_internal_current_profile(struct hidpp10_device *dev,
int16_t current_profile,
uint16_t current_profile,
uint8_t profile_type)
{
unsigned idx = dev->index;
union hidpp10_message profile = CMD_PROFILE(idx, SET_REGISTER_REQ);
int8_t page, offset;
struct hidpp10_directory directory[16]; /* completely random profile count */
int count = 0;
hidpp_log_raw(&dev->base, "Fetching the profiles' directory\n");
count = hidpp10_get_profile_directory(dev, directory,
ARRAY_LENGTH(directory));
if (count < 0)
return count;
hidpp_log_raw(&dev->base, "Setting current profile\n");
@@ -828,7 +877,7 @@ hidpp10_set_internal_current_profile(struct hidpp10_device *dev,
switch (profile_type) {
case PROFILE_TYPE_INDEX:
if (current_profile > count)
if (current_profile > dev->profile_count)
return -EINVAL;
profile.msg.parameters[1] = current_profile & 0xFF;
break;
@@ -851,7 +900,7 @@ hidpp10_set_internal_current_profile(struct hidpp10_device *dev,
}
int
hidpp10_set_current_profile(struct hidpp10_device *dev, int16_t current_profile)
hidpp10_set_current_profile(struct hidpp10_device *dev, uint16_t current_profile)
{
return hidpp10_set_internal_current_profile(dev,
current_profile,
@@ -1053,7 +1102,6 @@ hidpp10_onboard_profiles_macro_next(struct hidpp10_device *device,
break;
case HIDPP10_MACRO_END:
step = 1;
return 0;
default:
if (macro->any.type >= 0x80 && macro->any.type <= 0xFE) {
@@ -1405,8 +1453,8 @@ hidpp10_profile_set_names(struct hidpp10_device *dev, struct hidpp10_profile *pr
}
}
int
hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_profile *profile_return)
static int
hidpp10_read_profile(struct hidpp10_device *dev, uint8_t number)
{
uint8_t page_data[HIDPP10_PAGE_SIZE];
union _hidpp10_profile_data *data = (union _hidpp10_profile_data *)page_data;
@@ -1416,9 +1464,7 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
size_t i;
int res;
struct hidpp10_profile *profile;
struct hidpp10_directory directory[16]; /* completely random profile count */
union _hidpp10_button_binding *buttons;
int count = 0;
uint8_t page;
/* Page 0 is RAM
@@ -1432,19 +1478,30 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
hidpp_log_raw(&dev->base, "Fetching profile %d\n", number);
count = hidpp10_get_profile_directory(dev, directory,
ARRAY_LENGTH(directory));
if (count < 0)
return count;
if (count == 0 || dev->profile_type == HIDPP10_PROFILE_UNKNOWN)
if (dev->profile_type == HIDPP10_PROFILE_UNKNOWN)
return -ENOTSUP;
if (number >= count) {
hidpp_log_error(&dev->base, "Profile number %d not in the directory.\n", number);
if (number >= dev->profile_count) {
hidpp_log_error(&dev->base, "Profile number %d is not supported.\n", number);
return -EINVAL;
}
profile = &dev->profiles[number];
if (!profile->page) {
unsigned long pages = 0xffff;
unsigned int i;
/* pages 0 and 1 are ROM and directory so they are reserved */
long_clear_bit(&pages, 0);
long_clear_bit(&pages, 1);
for (i = 0; i < dev->profile_count; i++)
long_clear_bit(&pages, dev->profiles[i].page);
page = ffsl(pages) - 1;
profile->page = page;
}
switch (dev->profile_type) {
case HIDPP10_PROFILE_G500:
buttons = p500->buttons;
@@ -1460,19 +1517,18 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
return -EINVAL;
}
profile = &dev->profiles[number];
if (!profile->initialized) {
page = directory[number].page;
page = profile->page;
res = hidpp10_read_page(dev, page, page_data);
if (res == -EILSEQ) {
/*
* if the CRC is wrong, the mouse still handles the
* profile. Warn the user.
*/
hidpp_log_info(&dev->base,
"Profile %d has a wrong CRC, assuming valid.\n",
number);
if (profile->enabled)
hidpp_log_info(&dev->base,
"Profile %d has a wrong CRC, assuming valid.\n",
number);
res = 0;
}
if (res)
@@ -1571,8 +1627,21 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
}
}
*profile_return = *profile;
return 0;
}
int
hidpp10_get_profile(struct hidpp10_device *dev, uint8_t number, struct hidpp10_profile *profile_return)
{
if (dev->profile_type == HIDPP10_PROFILE_UNKNOWN)
return -ENOTSUP;
if (number >= dev->profile_count) {
hidpp_log_error(&dev->base, "Profile number %d is not supported.\n", number);
return -EINVAL;
}
*profile_return = dev->profiles[number];
return 0;
}
@@ -1622,7 +1691,7 @@ hidpp10_onboard_profiles_get_code_from_special(enum ratbag_button_action_special
}
int
hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_profile *profile)
hidpp10_set_profile(struct hidpp10_device *dev, uint8_t number, struct hidpp10_profile *profile)
{
uint8_t page_data[HIDPP10_PAGE_SIZE];
union _hidpp10_profile_data *data = (union _hidpp10_profile_data *)page_data;
@@ -1630,27 +1699,24 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
struct _hidpp10_profile_700 *p700 = &data->profile_700;
struct _hidpp10_profile_9 *p9 = &data->profile_9;
int res;
struct hidpp10_directory directory[16]; /* completely random profile count */
union _hidpp10_button_binding *buttons;
int count = 0;
uint16_t crc;
uint8_t page;
hidpp_log_raw(&dev->base, "Fetching profile %d\n", number);
count = hidpp10_get_profile_directory(dev, directory,
ARRAY_LENGTH(directory));
if (count < 0)
return count;
if (count == 0 || dev->profile_type == HIDPP10_PROFILE_UNKNOWN)
if (dev->profile_type == HIDPP10_PROFILE_UNKNOWN)
return -ENOTSUP;
if (number >= count) {
hidpp_log_error(&dev->base, "Profile number %d not in the directory.\n", number);
if (number >= dev->profile_count) {
hidpp_log_error(&dev->base, "Profile number %d is incorrect.\n", number);
return -EINVAL;
}
/* something went wrong */
if (!profile->page)
return -ENOTSUP;
memset(page_data, 0xff, sizeof(page_data));
switch (dev->profile_type) {
@@ -1665,6 +1731,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
return -ENOTSUP;
}
@@ -1675,7 +1742,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
case HIDPP10_PROFILE_G9:
/* we do not know the actual values of the remaining field right now
* so pre-fill with the current data */
res = hidpp10_read_page(dev, directory[number].page, page_data);
res = hidpp10_read_page(dev, profile->page, page_data);
if (res)
return res;
break;
@@ -1685,6 +1752,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
return -ENOTSUP;
}
switch (dev->profile_type) {
@@ -1702,7 +1770,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
break;
case HIDPP10_PROFILE_G700:
p700->default_dpi_mode = profile->default_dpi_mode;
p700->usb_refresh_rate = 1000 / profile->refresh_rate;
p700->usb_refresh_rate = profile->refresh_rate ? 1000 / profile->refresh_rate : 0;
hidpp10_write_dpi_modes_8_dual(dev, profile, p700->dpi_modes, PROFILE_NUM_DPI_MODES);
hidpp10_write_buttons(dev, profile, buttons, PROFILE_NUM_BUTTONS);
@@ -1721,6 +1789,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
break;
default:
hidpp_log_error(&dev->base, "This should never happen, complain to your maintainer.\n");
return -ENOTSUP;
}
crc = hidpp_crc_ccitt(page_data, HIDPP10_PAGE_SIZE - 2);
@@ -1743,6 +1812,13 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
if (res < 0)
return res;
if (profile->enabled != dev->profiles[number].enabled) {
dev->profiles[number].enabled = profile->enabled;
res = hidpp10_write_profile_directory(dev);
if (res < 0)
return res;
}
res = hidpp10_send_hot_payload(dev,
0x00, 0x0000, /* destination: RAM */
page_data,
@@ -1750,7 +1826,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
if (res < 0)
return res;
page = directory[number].page;
page = profile->page;
/* according to the spec, a profile can have an offset.
* For all the devices we know, they all start at 0x0000 */
res = hidpp10_erase_memory(dev, page);
@@ -1782,6 +1858,7 @@ hidpp10_set_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
if (res < 0)
return res;
dev->profiles[number] = *profile;
return res;
}
@@ -2110,6 +2187,9 @@ hidpp10_get_usb_refresh_rate(struct hidpp10_device *dev,
if (res)
return res;
if (!refresh.msg.parameters[0])
return -EINVAL;
*rate = 1000/refresh.msg.parameters[0];
return 0;
@@ -2626,14 +2706,10 @@ hidpp10_get_device_info(struct hidpp10_device *dev)
{
uint32_t feature_mask, notifications;
uint8_t reflect;
int i;
uint16_t xres, yres;
uint16_t refresh_rate;
enum hidpp10_led_status led[6];
int8_t current_profile;
struct hidpp10_profile profiles[HIDPP10_NUM_PROFILES];
int count;
struct hidpp10_directory directory[16];
uint8_t current_profile;
hidpp10_get_individual_features(dev, &feature_mask);
hidpp10_get_hidpp_notifications(dev, &notifications);
@@ -2645,18 +2721,14 @@ hidpp10_get_device_info(struct hidpp10_device *dev)
hidpp10_get_optical_sensor_settings(dev, &reflect);
hidpp10_get_current_profile(dev, &current_profile);
count = hidpp10_get_profile_directory(dev, directory,
ARRAY_LENGTH(directory));
for (i = 0; i < count && i < HIDPP10_NUM_PROFILES; i++)
hidpp10_get_profile(dev, i, &profiles[i]);
return 0;
}
struct hidpp10_device*
hidpp10_device_new(const struct hidpp_device *base, int idx,
enum hidpp10_profile_type type)
hidpp10_device_new(const struct hidpp_device *base,
int idx,
enum hidpp10_profile_type type,
unsigned int profile_count)
{
struct hidpp10_device *dev;
@@ -2665,6 +2737,8 @@ hidpp10_device_new(const struct hidpp_device *base, int idx,
dev->index = idx;
dev->base = *base;
dev->profile_type = type;
dev->profile_count = profile_count;
dev->profiles = zalloc(dev->profile_count * sizeof(struct hidpp10_profile));
if (hidpp10_get_device_info(dev) != 0) {
hidpp10_device_destroy(dev);
@@ -2674,6 +2748,19 @@ hidpp10_device_new(const struct hidpp_device *base, int idx,
return dev;
}
int
hidpp10_device_read_profiles(struct hidpp10_device *dev)
{
unsigned int i;
hidpp10_read_profile_directory(dev);
for (i = 0; i < dev->profile_count && i < HIDPP10_NUM_PROFILES; i++)
hidpp10_read_profile(dev, i);
return 0;
}
void
hidpp10_device_destroy(struct hidpp10_device *dev)
{
@@ -2682,19 +2769,15 @@ hidpp10_device_destroy(struct hidpp10_device *dev)
if (dev->dpi_table)
free(dev->dpi_table);
if (dev->profile_directory)
free(dev->profile_directory);
if (dev->profiles) {
for (i = 0; i < dev->profile_count; i++) {
ARRAY_FOR_EACH(dev->profiles[i].macros, macro) {
if (*macro) {
free(*macro);
*macro = NULL;
}
for (i = 0; i < dev->profile_count; i++) {
ARRAY_FOR_EACH(dev->profiles[i].macros, macro) {
if (*macro) {
free(*macro);
*macro = NULL;
}
}
free(dev->profiles);
}
free(dev->profiles);
free(dev);
}

View File

@@ -58,16 +58,20 @@ struct hidpp10_device {
struct hidpp_device base;
unsigned index;
uint8_t dpi_count;
struct hidpp10_dpi_mapping *dpi_table; /* must be null terminated */
struct hidpp10_directory *profile_directory; /* must be null terminated */
struct hidpp10_dpi_mapping *dpi_table;
enum hidpp10_profile_type profile_type;
struct hidpp10_profile *profiles;
unsigned int profile_count;
};
struct hidpp10_device*
hidpp10_device_new(const struct hidpp_device *base, int idx,
enum hidpp10_profile_type type);
hidpp10_device_new(const struct hidpp_device *base,
int idx,
enum hidpp10_profile_type type,
unsigned int profile_count);
int
hidpp10_device_read_profiles(struct hidpp10_device *dev);
void
hidpp10_device_destroy(struct hidpp10_device *dev);
@@ -101,6 +105,22 @@ int
hidpp10_build_dpi_table_from_dpi_info(struct hidpp10_device *dev,
const char *str_dpi);
/**
* Returns the lowest dpi stored in the dpi mapping table generated by
* hidpp10_build_dpi_table_from_list() or
* hidpp10_build_dpi_table_from_dpi_info()
*/
unsigned int
hidpp10_dpi_table_get_min_dpi(struct hidpp10_device *dev);
/**
* Returns the highest dpi stored in the dpi mapping table generated by
* hidpp10_build_dpi_table_from_list() or
* hidpp10_build_dpi_table_from_dpi_info()
*/
unsigned int
hidpp10_dpi_table_get_max_dpi(struct hidpp10_device *dev);
/* -------------------------------------------------------------------------- */
/* 0x00: Enable HID++ Notifications */
/* -------------------------------------------------------------------------- */
@@ -447,6 +467,8 @@ union hidpp10_macro_data {
_Static_assert(sizeof(union hidpp10_macro_data) == 5, "Invalid size");
struct hidpp10_profile {
uint8_t page;
uint8_t offset;
struct {
uint16_t xres;
uint16_t yres;
@@ -496,6 +518,7 @@ struct hidpp10_profile {
size_t num_leds;
unsigned int initialized;
bool enabled;
};
struct hidpp10_directory {
@@ -505,22 +528,17 @@ struct hidpp10_directory {
} __attribute__((packed));
int
hidpp10_get_profile_directory(struct hidpp10_device *dev,
struct hidpp10_directory *out,
size_t nelems);
hidpp10_get_current_profile(struct hidpp10_device *dev, uint8_t *current_profile);
int
hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile);
hidpp10_set_current_profile(struct hidpp10_device *dev, uint16_t current_profile);
int
hidpp10_set_current_profile(struct hidpp10_device *dev, int16_t current_profile);
int
hidpp10_get_profile(struct hidpp10_device *dev, int8_t number,
hidpp10_get_profile(struct hidpp10_device *dev, uint8_t number,
struct hidpp10_profile *profile);
int
hidpp10_set_profile(struct hidpp10_device *dev, int8_t number,
hidpp10_set_profile(struct hidpp10_device *dev, uint8_t number,
struct hidpp10_profile *profile);
enum ratbag_button_action_special

View File

@@ -130,13 +130,13 @@ hidpp20_request_command_allow_error(struct hidpp20_device *device, union hidpp20
hidpp_log_debug(&device->base,
" HID++ error from the device (%d): %s (%02x)\n",
read_buffer.msg.device_idx,
hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code",
hidpp20_errors[hidpp_err] ? hidpp20_errors[hidpp_err] : "Undocumented error code",
hidpp_err);
else
hidpp_log_error(&device->base,
" HID++ error from the device (%d): %s (%02x)\n",
read_buffer.msg.device_idx,
hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code",
hidpp20_errors[hidpp_err] ? hidpp20_errors[hidpp_err] : "Undocumented error code",
hidpp_err);
break;
}
@@ -241,7 +241,7 @@ hidpp20_root_get_protocol_version(struct hidpp20_device *device,
rc = hidpp20_request_command_allow_error(device, &msg, true);
if (rc == ERR_INVALID_SUBID) {
if (rc == HIDPP10_ERR_INVALID_SUBID) {
*major = 1;
*minor = 0;
return 0;
@@ -785,12 +785,15 @@ hidpp20_special_key_mouse_set_control(struct hidpp20_device *device,
return -ENOTSUP;
msg.msg.sub_id = feature_index;
msg.msg.parameters[2] |= 0x02;
if (control->reporting.divert)
msg.msg.parameters[2] |= 0x03;
msg.msg.parameters[2] |= 0x01;
msg.msg.parameters[2] |= 0x08;
if (control->reporting.persist)
msg.msg.parameters[2] |= 0x0c;
msg.msg.parameters[2] |= 0x04;
msg.msg.parameters[2] |= 0x20;
if (control->reporting.raw_XY)
msg.msg.parameters[2] |= 0x20;
msg.msg.parameters[2] |= 0x10;
return hidpp20_request_command(device, &msg);
}
@@ -887,8 +890,8 @@ hidpp20_adjustable_dpi_get_dpi_list(struct hidpp20_device *device,
if (value > 0xe000) {
sensor->dpi_steps = value - 0xe000;
} else {
sensor->dpi_min = value < sensor->dpi_min ? value : sensor->dpi_min;
sensor->dpi_max = value > sensor->dpi_max ? value : sensor->dpi_max;
sensor->dpi_min = min(value, sensor->dpi_min);
sensor->dpi_max = max(value, sensor->dpi_max);
sensor->dpi_list[dpi_index++] = value;
}
assert(sensor->dpi_list[dpi_index] == 0x0000);
@@ -975,7 +978,6 @@ int hidpp20_adjustable_dpi_get_sensors(struct hidpp20_device *device,
*sensors_list = s_list;
return num_sensors;
err:
num_sensors = 0;
free(s_list);
return rc > 0 ? -EPROTO : rc;
}
@@ -1296,6 +1298,61 @@ hidpp20_onboard_profiles_get_current_profile(struct hidpp20_device *device)
return msg.msg.parameters[1];
}
int
hidpp20_onboard_profiles_set_current_dpi_index(struct hidpp20_device *device,
uint8_t index)
{
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_SET_CURRENT_DPI_INDEX,
.msg.parameters[0] = index,
};
if (index > 4)
return -EINVAL;
feature_index = hidpp_root_get_feature_idx(device,
HIDPP_PAGE_ONBOARD_PROFILES);
if (feature_index == 0)
return -ENOTSUP;
msg.msg.sub_id = feature_index;
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return 0;
}
int
hidpp20_onboard_profiles_get_current_dpi_index(struct hidpp20_device *device)
{
uint8_t feature_index;
int rc;
union hidpp20_message msg = {
.msg.report_id = REPORT_ID_SHORT,
.msg.device_idx = device->index,
.msg.address = CMD_ONBOARD_PROFILES_GET_CURRENT_DPI_INDEX,
};
feature_index = hidpp_root_get_feature_idx(device,
HIDPP_PAGE_ONBOARD_PROFILES);
if (feature_index == 0)
return -ENOTSUP;
msg.msg.sub_id = feature_index;
rc = hidpp20_request_command(device, &msg);
if (rc)
return rc;
return msg.msg.parameters[0];
}
int
hidpp20_onboard_profiles_set_current_profile(struct hidpp20_device *device,
uint8_t index)
@@ -1457,7 +1514,6 @@ hidpp20_onboard_profiles_macro_next(struct hidpp20_device *device,
rc = -EAGAIN;
break;
case HIDPP20_MACRO_END:
step = 1;
return 0;
default:
hidpp_log_error(&device->base, "unknown tag: 0x%02x\n", macro->any.type);
@@ -1554,7 +1610,7 @@ hidpp20_onboard_profiles_parse_macro(struct hidpp20_device *device,
int rc;
rc = hidpp20_onboard_profiles_read_macro(device, page, offset, &macro);
if (rc < 0)
if (rc)
return rc;
count = rc;
@@ -1626,12 +1682,14 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
0x00,
offset,
data + offset);
if (rc < 0)
if (rc < 0) {
hidpp20_onboard_profiles_destroy(profiles);
return rc;
}
}
for (i = 0; i < profiles->num_profiles; i++) {
uint8_t *d = data + offset + 4 * i;
uint8_t *d = data + 4 * i;
if (d[0] == 0xFF && d[1] == 0xFF)
break;
@@ -1646,8 +1704,7 @@ hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
}
void
hidpp20_onboard_profiles_destroy(struct hidpp20_device *device,
struct hidpp20_profiles *profiles_list)
hidpp20_onboard_profiles_destroy(struct hidpp20_profiles *profiles_list)
{
struct hidpp20_profile *profile;
union hidpp20_macro_data **macro;
@@ -1725,18 +1782,14 @@ hidpp20_onboard_profiles_find_and_read_profile(struct hidpp20_device *device,
}
static int
hidpp20_onboard_profiles_enable_profile(struct hidpp20_device *device,
unsigned int index,
struct hidpp20_profiles *profiles_list)
hidpp20_onboard_profiles_set_enable_profile(struct hidpp20_device *device,
unsigned int index,
struct hidpp20_profiles *profiles_list)
{
unsigned int i, buffer_index = 0;
uint8_t data[HIDPP20_PROFILE_SIZE] = {0};
if (profiles_list->profiles[index].enabled)
return 0;
profiles_list->profiles[index].index = index + 1;
profiles_list->profiles[index].enabled = 0x01;
for (i = 0; i < profiles_list->num_profiles; i++) {
data[buffer_index++] = 0x00;
@@ -2034,7 +2087,7 @@ int hidpp20_onboard_profiles_write(struct hidpp20_device *device,
if (rc < 0)
return rc;
rc = hidpp20_onboard_profiles_enable_profile(device, index, profiles_list);
rc = hidpp20_onboard_profiles_set_enable_profile(device, index, profiles_list);
if (rc < 0)
return rc;

View File

@@ -472,6 +472,7 @@ struct hidpp20_profile {
unsigned report_rate;
unsigned default_dpi;
unsigned switched_dpi;
unsigned current_dpi;
uint16_t dpi[HIDPP20_DPI_COUNT];
union hidpp20_button_binding buttons[32];
union hidpp20_macro_data *macros[32];
@@ -504,8 +505,7 @@ int hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
* free a list of profiles allocated by hidpp20_onboard_profiles_allocate()
*/
void
hidpp20_onboard_profiles_destroy(struct hidpp20_device *device,
struct hidpp20_profiles *profiles_list);
hidpp20_onboard_profiles_destroy(struct hidpp20_profiles *profiles_list);
/**
* return the current profile index or a negative error.
@@ -522,6 +522,22 @@ int
hidpp20_onboard_profiles_set_current_profile(struct hidpp20_device *device,
uint8_t index);
/**
* return the current dpi index of the current active profile
* or a negative error.
*/
int hidpp20_onboard_profiles_get_current_dpi_index(struct hidpp20_device *device);
/**
* Sets the current dpi index on the current active profile.
* Indexes are 0-indexed.
*
* return 0 or a negative error.
*/
int
hidpp20_onboard_profiles_set_current_dpi_index(struct hidpp20_device *device,
uint8_t index);
/**
* parse a given profile from the mouse and fill in the right profile in
* profiles_list.

View File

@@ -146,7 +146,7 @@ hidpp10_init(int fd)
hidpp_device_init(&base, fd);
return hidpp10_device_new(&base, HIDPP_RECEIVER_IDX,
HIDPP10_PROFILE_UNKNOWN);
HIDPP10_PROFILE_UNKNOWN, 1);
}
_EXPORT_ int
@@ -201,8 +201,7 @@ lur_receiver_enumerate(struct lur_receiver *lur,
uint32_t serial;
bool is_new_device = true;
d = hidpp10_device_new(&base, i,
HIDPP10_PROFILE_UNKNOWN);
d = hidpp10_device_new(&base, i, HIDPP10_PROFILE_UNKNOWN, 1);
if (!d)
continue;

View File

@@ -1405,7 +1405,7 @@ ratbag_find_hidraw_node(struct ratbag_device *device,
udev_enumerate_add_match_parent(e, parent_udev);
udev_enumerate_scan_devices(e);
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
_cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
_cleanup_(udev_device_unrefp) struct udev_device *udev_device = NULL;
path = udev_list_entry_get_name(entry);
udev_device = udev_device_new_from_syspath(udev, path);

View File

@@ -78,6 +78,8 @@ struct ratbag {
enum ratbag_log_priority log_priority;
};
#define MAX_CAP 1000
struct ratbag_device {
char *name;
void *userdata;
@@ -88,7 +90,7 @@ struct ratbag_device {
struct input_id ids;
struct ratbag_driver *driver;
struct ratbag *ratbag;
unsigned long capabilities;
unsigned long capabilities[NLONGS(MAX_CAP)];
unsigned num_profiles;
struct list profiles;
@@ -142,6 +144,15 @@ struct ratbag_driver {
*/
int (*commit)(struct ratbag_device *device);
/**
* Callback called when the device doesn't have the udev property
* RATBAG_SVG.
*
* The returned value must not be free by the caller, the driver
* has to free it during .remove().
*/
const char *(*get_svg_name)(const struct ratbag_device *device);
/**
* Callback called when a read profile is requested by the
* caller of the library.
@@ -213,7 +224,7 @@ struct ratbag_driver {
unsigned int brightness);
/* private */
int (*test_probe)(struct ratbag_device *device, void *data);
int (*test_probe)(struct ratbag_device *device, const void *data);
struct list link;
};
@@ -222,6 +233,8 @@ struct ratbag_resolution {
struct ratbag_profile *profile;
int refcount;
void *userdata;
unsigned int dpi_max; /**< max resolution in dpi */
unsigned int dpi_min; /**< min resolution in dpi */
unsigned int dpi_x; /**< x resolution in dpi */
unsigned int dpi_y; /**< y resolution in dpi */
unsigned int hz; /**< report rate in Hz */
@@ -355,7 +368,7 @@ ratbag_set_drv_data(struct ratbag_device *device, void *drv_data)
}
static inline void *
ratbag_get_drv_data(struct ratbag_device *device)
ratbag_get_drv_data(const struct ratbag_device *device)
{
return device->drv_data;
}
@@ -419,10 +432,19 @@ ratbag_resolution_init(struct ratbag_profile *profile, int index,
res->is_active = false;
res->is_default = false;
res->capabilities = 0;
res->dpi_min = 0;
res->dpi_max = 0;
return res;
}
static inline void
ratbag_resolution_set_range(struct ratbag_resolution *res, int min, int max)
{
res->dpi_min = min;
res->dpi_max = max;
}
static inline void
ratbag_resolution_set_cap(struct ratbag_resolution *res,
enum ratbag_resolution_capability cap)
@@ -481,7 +503,7 @@ ratbag_device_get_udev_property(const struct ratbag_device* device,
bool
ratbag_assign_driver(struct ratbag_device *device,
const struct input_id *dev_id,
struct ratbag_test_device *test_device);
const struct ratbag_test_device *test_device);
void
ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver);

View File

@@ -50,7 +50,7 @@ ratbag_register_test_drivers(struct ratbag *ratbag)
LIBRATBAG_EXPORT struct ratbag_device*
ratbag_device_new_test_device(struct ratbag *ratbag,
struct ratbag_test_device *test_device)
const struct ratbag_test_device *test_device)
{
struct ratbag_device* device = NULL;
#if BUILD_TESTS

View File

@@ -31,12 +31,19 @@
#define RATBAG_TEST_MAX_RESOLUTIONS 8
#define RATBAG_TEST_MAX_LEDS 8
struct ratbag_test_macro_event {
enum ratbag_macro_event_type type;
unsigned int value;
};
struct ratbag_test_button {
enum ratbag_button_action_type type;
enum ratbag_button_type button_type;
enum ratbag_button_action_type action_type;
union {
int button;
int key;
enum ratbag_button_action_special special;
struct ratbag_test_macro_event macro[24];
};
};
@@ -68,6 +75,7 @@ struct ratbag_test_profile {
struct ratbag_test_led leds[RATBAG_TEST_MAX_LEDS];
bool active;
bool dflt;
bool disabled;
};
struct ratbag_test_device {
@@ -75,11 +83,12 @@ struct ratbag_test_device {
unsigned int num_resolutions;
unsigned int num_buttons;
unsigned int num_leds;
const char *svg;
struct ratbag_test_profile profiles[RATBAG_TEST_MAX_PROFILES];
void (*destroyed)(struct ratbag_device *device, void *data);
void *destroyed_data;
};
struct ratbag_device* ratbag_device_new_test_device(struct ratbag *ratbag,
struct ratbag_test_device *test_device);
const struct ratbag_test_device *test_device);

View File

@@ -29,6 +29,8 @@
#include <unistd.h>
#include <libudev.h>
#include "shared-macro.h"
/*
* This list data structure is a verbatim copy from wayland-util.h from the
* Wayland project; except that wl_ prefix has been removed.
@@ -44,16 +46,6 @@ void list_insert(struct list *list, struct list *elm);
void list_remove(struct list *elm);
int list_empty(const struct list *list);
#ifdef __GNUC__
#define container_of(ptr, sample, member) \
(__typeof__(sample))((char *)(ptr) - \
((char *)&(sample)->member - (char *)(sample)))
#else
#define container_of(ptr, sample, member) \
(void *)((char *)(ptr) - \
((char *)&(sample)->member - (char *)(sample)))
#endif
#define list_for_each(pos, head, member) \
for (pos = 0, pos = container_of((head)->next, pos, member); \
&pos->member != (head); \
@@ -67,45 +59,6 @@ int list_empty(const struct list *list);
pos = tmp, \
tmp = container_of(pos->member.next, tmp, member))
#define LONG_BITS (sizeof(long) * 8)
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define ARRAY_FOR_EACH(_arr, _elem) \
for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
#define AS_MASK(v) (1 << (v))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
static inline void
cleanup_free(void *p) {
free(*(void**)p);
}
static inline void
cleanup_close(int *p) {
close(*p);
}
static inline void
cleanup_udev_unref(struct udev **udev) {
if (*udev)
udev_unref(*udev);
}
static inline void
cleanup_udev_device_unref(struct udev_device **udev_device) {
if (*udev_device)
udev_device_unref(*udev_device);
}
#define _cleanup_(x) __attribute__((cleanup(x)))
#define _cleanup_free_ _cleanup_(cleanup_free)
#define _cleanup_close_ _cleanup_(cleanup_close)
#define _cleanup_udev_unref_ _cleanup_(cleanup_udev_unref)
#define _cleanup_udev_device_unref_ _cleanup_(cleanup_udev_device_unref)
static inline char*
strncpy_safe(char *dest, const char *src, size_t n)
{

View File

@@ -290,7 +290,7 @@ static inline bool
ratbag_test_driver(struct ratbag_device *device,
const struct input_id *dev_id,
const char *driver_name,
struct ratbag_test_device *test_device)
const struct ratbag_test_device *test_device)
{
struct ratbag *ratbag = device->ratbag;
struct ratbag_driver *driver;
@@ -328,9 +328,8 @@ ratbag_test_driver(struct ratbag_device *device,
log_error(ratbag, "%s: error opening hidraw node (%s)\n",
device->name, strerror(-rc));
error:
device->driver = NULL;
error:
return false;
}
@@ -353,7 +352,7 @@ ratbag_driver_fallback_logitech(struct ratbag_device *device,
bool
ratbag_assign_driver(struct ratbag_device *device,
const struct input_id *dev_id,
struct ratbag_test_device *test_device)
const struct ratbag_test_device *test_device)
{
bool rc;
const char *driver_name;
@@ -373,17 +372,21 @@ ratbag_assign_driver(struct ratbag_device *device,
return rc;
}
static inline char*
get_device_name(struct udev_device *device)
static int
get_device_name(struct udev_device *device,
char *name, size_t sz)
{
const char *prop;
prop = udev_prop_value(device, "NAME");
if (!prop)
return NULL;
return -EINVAL;
/* udev name is enclosed by " */
return strndup(&prop[1], strlen(prop) - 2);
sz = min(sz, strlen(prop) - 1);
snprintf(name, sz, "%s", &prop[1]);
return 0;
}
static inline int
@@ -413,7 +416,7 @@ ratbag_device_new_from_udev_device(struct ratbag *ratbag,
{
struct ratbag_device *device = NULL;
enum ratbag_error_code error = RATBAG_ERROR_DEVICE;
_cleanup_free_ char *name = NULL;
char name[128];
struct input_id id;
assert(ratbag != NULL);
@@ -426,8 +429,7 @@ ratbag_device_new_from_udev_device(struct ratbag *ratbag,
if (get_product_id(udev_device, &id) != 0)
goto out_err;
name = get_device_name(udev_device);
if (!name)
if (get_device_name(udev_device, name, sizeof(name)) != 0)
goto out_err;
device = ratbag_device_new(ratbag, udev_device, name, &id);
@@ -481,7 +483,13 @@ ratbag_device_get_name(const struct ratbag_device* device)
LIBRATBAG_EXPORT const char *
ratbag_device_get_svg_name(const struct ratbag_device* device)
{
return udev_prop_value(device->udev_device, "RATBAG_SVG");
const char *name;
name = udev_prop_value(device->udev_device, "RATBAG_SVG");
if (!name && device->driver->get_svg_name)
name = device->driver->get_svg_name(device);
return name;
}
const char *
@@ -643,8 +651,9 @@ ratbag_create_profile(struct ratbag_device *device,
profile->refcount = 0;
profile->device = device;
profile->index = index;
profile->resolution.modes = zalloc(num_resolutions *
sizeof(*profile->resolution.modes));
if (num_resolutions)
profile->resolution.modes = zalloc(num_resolutions *
sizeof(*profile->resolution.modes));
profile->resolution.num_modes = num_resolutions;
profile->is_enabled = true;
@@ -680,15 +689,19 @@ ratbag_device_init_profiles(struct ratbag_device *device,
device->num_profiles = num_profiles;
if (num_profiles > 1) {
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_PROFILE);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE);
/* having more than one profile means we can remap the buttons
* at least */
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_KEY);
}
if (num_resolutions > 1)
if (num_resolutions > 1) {
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_RESOLUTION);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION);
}
if (num_leds > 1)
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_LED);
@@ -808,17 +821,31 @@ void
ratbag_device_set_capability(struct ratbag_device *device,
enum ratbag_device_capability cap)
{
device->capabilities |= (1UL << cap);
if (cap == RATBAG_DEVICE_CAP_NONE || cap >= MAX_CAP)
abort();
if (cap != RATBAG_DEVICE_CAP_QUERY_CONFIGURATION && cap % 100) {
enum ratbag_device_capability parent_cap = (cap/100) * 100;
if (!long_bit_is_set(device->capabilities, parent_cap)) {
log_bug_libratbag(device->ratbag,
"Cap %d requires setting %d\n",
cap, parent_cap);
abort();
}
}
long_set_bit(device->capabilities, cap);
}
LIBRATBAG_EXPORT int
ratbag_device_has_capability(const struct ratbag_device *device,
enum ratbag_device_capability cap)
{
if (cap == RATBAG_DEVICE_CAP_NONE)
if (cap == RATBAG_DEVICE_CAP_NONE || cap >= MAX_CAP)
abort();
return !!(device->capabilities & (1UL << cap));
return long_bit_is_set(device->capabilities, cap);
}
static inline enum ratbag_error_code
@@ -1075,6 +1102,18 @@ ratbag_resolution_get_dpi(struct ratbag_resolution *resolution)
return resolution->dpi_x;
}
LIBRATBAG_EXPORT int
ratbag_resolution_get_dpi_maximum(struct ratbag_resolution *resolution)
{
return resolution->dpi_max;
}
LIBRATBAG_EXPORT int
ratbag_resolution_get_dpi_minimum(struct ratbag_resolution *resolution)
{
return resolution->dpi_min;
}
LIBRATBAG_EXPORT int
ratbag_resolution_get_dpi_x(struct ratbag_resolution *resolution)
{
@@ -1102,9 +1141,15 @@ ratbag_resolution_is_active(const struct ratbag_resolution *resolution)
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_resolution_set_active(struct ratbag_resolution *resolution)
{
struct ratbag_profile *profile = resolution->profile;
unsigned int i;
for (i = 0; i < profile->resolution.num_modes; i++)
profile->resolution.modes[i].is_active = false;
resolution->is_active = true;
/* FIXME: call into the driver */
return RATBAG_ERROR_IMPLEMENTATION;
profile->dirty = true;
return RATBAG_SUCCESS;
}

View File

@@ -490,48 +490,6 @@ ratbag_device_get_svg_name(const struct ratbag_device* device);
*/
enum ratbag_device_capability {
RATBAG_DEVICE_CAP_NONE = 0,
/**
* The device can change resolution, either software-controlled or
* by a hardware button.
*
* FIXME: what about devices that only have hw buttons? can we
* query that, even if we can't switch it ourselves? Maybe better to
* have a separate cap for that then.
*/
RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION,
/**
* The device can switch between hardware profiles.
* A device with this capability can store multiple profiles in the
* hardware and provides the ability to switch between the profiles,
* possibly with a button.
* Devices without this capability will only have a single profile.
*/
RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE,
/**
* The device supports assigning button numbers, key events or key +
* modifier combinations.
*/
RATBAG_DEVICE_CAP_BUTTON_KEY,
/**
* The device supports assigning LED colors and effects
*/
RATBAG_DEVICE_CAP_LED,
/**
* The device supports user-defined key or button sequences.
*/
RATBAG_DEVICE_CAP_BUTTON_MACROS,
/**
* The device can have one profile assigned as a default profile.
* A default profile is the profile that is selected when the device
* is plugged in. Devices without this capability may select the
* last-used profile or a specific profile (usually the first).
*/
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
/**
* The device has the capability to query the current hardware
* configuration. If this capability is missing, libratbag cannot
@@ -549,6 +507,37 @@ enum ratbag_device_capability {
*/
RATBAG_DEVICE_CAP_QUERY_CONFIGURATION,
/**
* The device provides read and/or write access to one or more
* resolutions.
*/
RATBAG_DEVICE_CAP_RESOLUTION = 100,
/**
* The device can change resolution, either software-controlled or
* by a hardware button.
*
* FIXME: what about devices that only have hw buttons? can we
* query that, even if we can't switch it ourselves? Maybe better to
* have a separate cap for that then.
*/
RATBAG_DEVICE_CAP_SWITCHABLE_RESOLUTION,
/**
* The device provides read and/or write access to one or more
* profiles.
*/
RATBAG_DEVICE_CAP_PROFILE = 200,
/**
* The device can switch between hardware profiles.
* A device with this capability can store multiple profiles in the
* hardware and provides the ability to switch between the profiles,
* possibly with a button.
* Devices without this capability will only have a single profile.
*/
RATBAG_DEVICE_CAP_SWITCHABLE_PROFILE,
/**
* The device has the capability to disable and enable profiles. While
* profiles are not immediately deleted after being disabled, it is not
@@ -557,6 +546,36 @@ enum ratbag_device_capability {
* changed the next time ratbag runs if profiles are disabled.
*/
RATBAG_DEVICE_CAP_DISABLE_PROFILE,
/**
* The device can have one profile assigned as a default profile.
* A default profile is the profile that is selected when the device
* is plugged in. Devices without this capability may select the
* last-used profile or a specific profile (usually the first).
*/
RATBAG_DEVICE_CAP_DEFAULT_PROFILE,
/**
* The device provides read and/or write access to one or more
* buttons.
*/
RATBAG_DEVICE_CAP_BUTTON = 300,
/**
* The device supports assigning button numbers, key events or key +
* modifier combinations.
*/
RATBAG_DEVICE_CAP_BUTTON_KEY,
/**
* The device supports user-defined key or button sequences.
*/
RATBAG_DEVICE_CAP_BUTTON_MACROS,
/**
* The device supports assigning LED colors and effects
*/
RATBAG_DEVICE_CAP_LED = 400,
};
/**
@@ -758,7 +777,7 @@ ratbag_profile_set_active(struct ratbag_profile *profile);
*
* Get the number of @ref ratbag_resolution available in this profile. A
* resolution mode is a tuple of (resolution, report rate), each mode can be
* fetched with ratbag_profile_get_resolution_by_idx().
* fetched with ratbag_profile_get_resolution().
*
* The returned value is the maximum number of modes available and thus
* identical for all profiles. However, some of the modes may not be
@@ -937,6 +956,32 @@ ratbag_resolution_set_dpi_xy(struct ratbag_resolution *resolution,
int
ratbag_resolution_get_dpi(struct ratbag_resolution *resolution);
/**
* @ingroup resolution
*
* Get the maximum allowed resolution in DPI for the resolution mode.
*
* @param resolution A previously initialized ratbag resolution
*
* @return The maximum resolution in dpi
* @retval 0 The maximum resolution is unknown to libratbag
*/
int
ratbag_resolution_get_dpi_maximum(struct ratbag_resolution *resolution);
/**
* @ingroup resolution
*
* Get the minimum allowed resolution in DPI for the resolution mode.
*
* @param resolution A previously initialized ratbag resolution
*
* @return The minimum resolution in dpi
* @retval 0 The minimum resolution is unknown to libratbag
*/
int
ratbag_resolution_get_dpi_minimum(struct ratbag_resolution *resolution);
/**
* @ingroup resolution
*
@@ -1189,10 +1234,6 @@ ratbag_button_get_type(struct ratbag_button *button);
* The type assigned to a button.
*/
enum ratbag_button_action_type {
/**
* Button action is unknown
*/
RATBAG_BUTTON_ACTION_TYPE_UNKNOWN = -1,
/**
* Button is disabled
*/
@@ -1214,6 +1255,10 @@ enum ratbag_button_action_type {
* Button sends a user-defined key or button sequence
*/
RATBAG_BUTTON_ACTION_TYPE_MACRO,
/**
* Button action is unknown
*/
RATBAG_BUTTON_ACTION_TYPE_UNKNOWN = 1000,
};
/**

View File

@@ -1,12 +0,0 @@
prefix=@prefix@
datadir=${prefix}/@datadir@
pkgdatadir=${datadir}/libratbag
libdir=${prefix}/@libdir@
includedir=${prefix}/@includedir@
Name: Libratbag
Description: Mouse configuration library
Version: @LIBRATBAG_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lratbag
Libs.private: -lm -lrt

View File

@@ -70,6 +70,8 @@ global:
ratbag_profile_set_enabled;
ratbag_profile_unref;
ratbag_resolution_get_dpi;
ratbag_resolution_get_dpi_maximum;
ratbag_resolution_get_dpi_minimum;
ratbag_resolution_get_dpi_x;
ratbag_resolution_get_dpi_y;
ratbag_resolution_get_report_rate;

287
src/shared-macro.h Normal file
View File

@@ -0,0 +1,287 @@
#pragma once
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
/*
* We require:
* sizeof(void*) == sizeof(long)
* sizeof(long) == 4 || sizeof(long) == 8
* sizeof(int) == 4
* The linux kernel requires the same from the toolchain, so this should work
* just fine.
*/
#if __SIZEOF_POINTER__ != __SIZEOF_LONG__
# error "sizeof(void*) != sizeof(long)"
#elif __SIZEOF_LONG__ != 4 && __SIZEOF_LONG__ != 8
# error "sizeof(long) != 4 && sizeof(long) != 8"
#elif __SIZEOF_INT__ != 4
# error "sizeof(int) != 4"
#endif
/*
* Shortcuts for gcc attributes. See GCC manual for details.
*/
#define _alignas_(_x) __attribute__((aligned(__alignof(_x))))
#define _alloc_(...) __attribute__((alloc_size(__VA_ARGS__)))
#define _cleanup_(_x) __attribute__((cleanup(_x)))
#define _const_ __attribute__((const))
#define _deprecated_ __attribute__((deprecated))
#define _hidden_ __attribute__((visibility("hidden")))
#define _likely_(_x) (__builtin_expect(!!(_x), 1))
#define _malloc_ __attribute__((malloc))
#define _packed_ __attribute__((packed))
#define _printf_(_a, _b) __attribute__((format (printf, _a, _b)))
#define _public_ __attribute__((visibility("default")))
#define _pure_ __attribute__((pure))
#define _sentinel_ __attribute__((sentinel))
#define _unlikely_(_x) (__builtin_expect(!!(_x), 0))
#define _unused_ __attribute__((unused))
#define _weak_ __attribute__((weak))
#define _weakref_(_x) __attribute__((weakref(#_x)))
/* container_of macro */
#ifdef __GNUC__
#define container_of(ptr, sample, member) \
(__typeof__(sample))((char *)(ptr) - \
((char *)&(sample)->member - (char *)(sample)))
#else
#define container_of(ptr, sample, member) \
(void *)((char *)(ptr) - \
((char *)&(sample)->member - (char *)(sample)))
#endif
#define LONG_BITS (sizeof(long) * 8)
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define ARRAY_FOR_EACH(_arr, _elem) \
for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
#define AS_MASK(v) (1 << (v))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
/*
* DECIMAL_TOKEN_MAX() - calculate maximum length of the decimal representation
* of an integer
* @_type: type of integer
*/
#define DECIMAL_TOKEN_MAX(_type) \
(1 + (sizeof(_type) <= 1 ? 3 : \
sizeof(_type) <= 2 ? 5 : \
sizeof(_type) <= 4 ? 10 : \
sizeof(_type) <= 8 ? 20 : \
sizeof(int[-2 * (sizeof(_type) > 8)])))
/*
* PROTECT_ERRNO: make sure a function protects errno
*/
static inline void reset_errno(int *saved_errno)
{
errno = *saved_errno;
}
#define PROTECT_ERRNO _cleanup_(reset_errno) _unused_ int saved_errno = errno
#define _cleanup_free_ _cleanup_(freep)
#define _cleanup_close_ _cleanup_(safe_closep)
/*
* DEFINE_TRIVIAL_CLEANUP_FUNC() - define helper suitable for _cleanup_()
* @_type: type of object to cleanup
* @_func: function to call on cleanup
*/
#define DEFINE_TRIVIAL_CLEANUP_FUNC(_type, _func) \
static inline void _func##p(_type *_p) \
{ \
if (*_p) \
_func(*_p); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref);
/*
* ELEMENTSOF() - number of array elements
* @_array: C array
*
* This calculates the number of elements (compared to the byte size) of
* the given C array. This returns (void) if the passed argument is not
* actually a valid C array (decided at compile time).
*/
#define ELEMENTSOF(_array) \
__extension__ (__builtin_choose_expr( \
!__builtin_types_compatible_p(typeof(_array), \
typeof(&*(_array))), \
sizeof(_array) / sizeof((_array)[0]), \
(void)0))
/*
* negative_errno() - return negative errno
*
* This helper should be used to shut up gcc if you know 'errno' is
* negative. Instead of "return -errno;", use "return negative_errno();"
* It will suppress bogus gcc warnings in case it assumes 'errno' might
* be 0 and thus the caller's error-handling might not be triggered.
*/
static inline int negative_errno(void)
{
return (errno <= 0) ? -EINVAL : -errno;
}
/*
* mfree() - free memory
* @mem: memory to free
*
* This is basically the same as free(), but returns NULL. This makes free()
* follow the same style as all our other destructors.
*/
static inline void *mfree(void *mem)
{
free(mem);
return NULL;
}
/*
* safe_close() - safe variant of close(2)
* @fd: fd to close
*
* This is the same as close(2), but allows passing negative FDs, which makes
* it a no-op. Furthermore, this always returns -1.
*/
static inline int safe_close(int fd)
{
if (fd >= 0) {
PROTECT_ERRNO;
close(fd);
}
return -1;
}
/*
* Miscellaneous cleanup helpers
* All these helpers are suitable for use with _cleanup_(). They call the helper
* they're named after on the variable marked for cleanup.
*/
static inline void freep(void *p)
{
free(*(void**)p);
}
static inline void safe_closep(int *fd)
{
safe_close(*fd);
}
/*
* streq() - test whether two strings are equal
* @_a: string A
* @_b: string B
*/
#define streq(_a, _b) (strcmp((_a), (_b)) == 0)
#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
/*
* streq_ptr() - test whether two strings are equal, considering NULL valid
* @a: string A or NULL
* @b: string B or NULL
*/
static inline bool streq_ptr(const char *a, const char *b)
{
return (a && b) ? streq(a, b) : (!a && !b);
}
/*
* startswith() - test prefix of a string
* @s: string to test
* @prefix: prefix to test for
*
* This returns a pointer to the first character in @s that follows @prefix. If
* @s does not start with @prefix, NULL is returned.
*/
static inline char *startswith(const char *s, const char *prefix)
{
size_t l;
l = strlen(prefix);
if (strncmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
/*
* safe_atou() - safe variant of strtoul()
* @s: string to parse
* @ret_u: output storage for parsed integer
*
* This is a sane and safe variant of strtoul(), which rejects any invalid
* input, or trailing garbage.
*
* Return: 0 on success, negative error code on failure.
*/
static inline int safe_atou(const char *s, unsigned int *ret_u)
{
char *x = NULL;
unsigned long l;
assert(s);
assert(ret_u);
errno = 0;
l = strtoul(s, &x, 0);
if (!x || x == s || *x || errno)
return errno > 0 ? -errno : -EINVAL;
if ((unsigned long)(unsigned int)l != l)
return -ERANGE;
*ret_u = (unsigned int)l;
return 0;
}
/*
* now() - returns current time in nano-seconds
* @clock: clock to use
*/
static inline uint64_t now(clockid_t clock)
{
struct timespec spec = {};
clock_gettime(clock, &spec);
return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec;
}

455
src/shared-rbtree.c Normal file
View File

@@ -0,0 +1,455 @@
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
/*
* Open Red-Black-Tree Implementation
* You're highly recommended to read a paper on rb-trees before reading this
* code. The reader is expected to be familiar with the different cases that
* might occur during insertion and removal of elements. The comments in this
* file do not contain a full prove for correctness.
*/
#include "config.h"
#include "shared-rbtree.h"
RBNode *rbnode_leftmost(RBNode *n) {
if (n)
while (n->left)
n = n->left;
return n;
}
RBNode *rbnode_rightmost(RBNode *n) {
if (n)
while (n->right)
n = n->right;
return n;
}
RBNode *rbtree_first(RBTree *t) {
return rbnode_leftmost(t->root);
}
RBNode *rbtree_last(RBTree *t) {
return rbnode_rightmost(t->root);
}
RBNode *rbnode_next(RBNode *n) {
RBNode *p;
if (!rbnode_linked(n))
return NULL;
if (n->right)
return rbnode_leftmost(n->right);
while ((p = rbnode_parent(n)) && n == p->right)
n = p;
return p;
}
RBNode *rbnode_prev(RBNode *n) {
RBNode *p;
if (!rbnode_linked(n))
return NULL;
if (n->left)
return rbnode_rightmost(n->left);
while ((p = rbnode_parent(n)) && n == p->left)
n = p;
return p;
}
static inline void rbnode_reparent(RBNode *n, RBNode *p, unsigned long c) {
/* change color and/or parent of a node */
rbtree_assert(!((unsigned long)p & 1));
rbtree_assert(c < 2);
n->__parent_and_color = (RBNode*)((unsigned long)p | c);
}
static inline void rbtree_reparent(RBTree *t, RBNode *p, RBNode *old, RBNode *new) {
/* change previous parent/root from old to new node */
if (p) {
if (p->left == old)
p->left = new;
else
p->right = new;
} else {
t->root = new;
}
}
static inline RBNode *rbtree_paint_one(RBTree *t, RBNode *n) {
RBNode *p, *g, *gg, *u, *x;
/*
* Paint a single node according to RB-Tree rules. The node must
* already be linked into the tree and painted red.
* We repaint the node or rotate the tree, if required. In case a
* recursive repaint is required, the next node to be re-painted
* is returned.
* p: parent
* g: grandparent
* gg: grandgrandparent
* u: uncle
* x: temporary
*/
/* node is red, so we can access the parent directly */
p = n->__parent_and_color;
if (!p) {
/* Case 1:
* We reached the root. Mark it black and be done. As all
* leaf-paths share the root, the ratio of black nodes on each
* path stays the same. */
rbnode_reparent(n, p, RBNODE_BLACK);
n = NULL;
} else if (rbnode_black(p)) {
/* Case 2:
* The parent is already black. As our node is red, we did not
* change the number of black nodes on any path, nor do we have
* multiple consecutive red nodes. */
n = NULL;
} else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */
g = p->__parent_and_color;
gg = rbnode_parent(g);
u = g->right;
if (u && rbnode_red(u)) {
/* Case 3:
* Parent and uncle are both red. We know the
* grandparent must be black then. Repaint parent and
* uncle black, the grandparent red and recurse into
* the grandparent. */
rbnode_reparent(p, g, RBNODE_BLACK);
rbnode_reparent(u, g, RBNODE_BLACK);
rbnode_reparent(g, gg, RBNODE_RED);
n = g;
} else {
/* parent is red, uncle is black */
if (n == p->right) {
/* Case 4:
* We're the right child. Rotate on parent to
* become left child, so we can handle it the
* same as case 5. */
x = n->left;
p->right = n->left;
n->left = p;
if (x)
rbnode_reparent(x, p, RBNODE_BLACK);
rbnode_reparent(p, n, RBNODE_RED);
p = n;
}
/* 'n' is invalid from here on! */
n = NULL;
/* Case 5:
* We're the red left child or a red parent, black
* grandparent and uncle. Rotate on grandparent and
* switch color with parent. Number of black nodes on
* each path stays the same, but we got rid of the
* double red path. As the grandparent is still black,
* we're done. */
x = p->right;
g->left = x;
p->right = g;
if (x)
rbnode_reparent(x, g, RBNODE_BLACK);
rbnode_reparent(p, gg, RBNODE_BLACK);
rbnode_reparent(g, p, RBNODE_RED);
rbtree_reparent(t, gg, g, p);
}
} else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */
g = p->__parent_and_color;
gg = rbnode_parent(g);
u = g->left;
if (u && rbnode_red(u)) {
rbnode_reparent(p, g, RBNODE_BLACK);
rbnode_reparent(u, g, RBNODE_BLACK);
rbnode_reparent(g, gg, RBNODE_RED);
n = g;
} else {
if (n == p->left) {
x = n->right;
p->left = n->right;
n->right = p;
if (x)
rbnode_reparent(x, p, RBNODE_BLACK);
rbnode_reparent(p, n, RBNODE_RED);
p = n;
}
n = NULL;
x = p->left;
g->right = x;
p->left = g;
if (x)
rbnode_reparent(x, g, RBNODE_BLACK);
rbnode_reparent(p, gg, RBNODE_BLACK);
rbnode_reparent(g, p, RBNODE_RED);
rbtree_reparent(t, gg, g, p);
}
}
return n;
}
static inline void rbtree_paint(RBTree *t, RBNode *n) {
while (n)
n = rbtree_paint_one(t, n);
}
void rbtree_add(RBTree *t, RBNode *p, RBNode **l, RBNode *n) {
n->__parent_and_color = p;
n->left = n->right = NULL;
*l = n;
rbtree_paint(t, n);
}
static inline RBNode *rbtree_rebalance_one(RBTree *t, RBNode *p, RBNode *n) {
RBNode *s, *x, *y, *g;
/*
* Rebalance tree after a node was removed. This happens only if you
* remove a black node and one path is now left with an unbalanced
* number or black nodes.
* This function assumes all paths through p and n have one black node
* less than all other paths. If recursive fixup is required, the
* current node is returned.
*/
if (n == p->left) {
s = p->right;
if (rbnode_red(s)) {
/* Case 3:
* We have a red node as sibling. Rotate it onto our
* side so we can later on turn it black. This way, we
* gain the additional black node in our path. */
g = rbnode_parent(p);
x = s->left;
p->right = x;
s->left = p;
rbnode_reparent(x, p, RBNODE_BLACK);
rbnode_reparent(s, g, rbnode_color(p));
rbnode_reparent(p, s, RBNODE_RED);
rbtree_reparent(t, g, p, s);
s = x;
}
x = s->right;
if (!x || rbnode_black(x)) {
y = s->left;
if (!y || rbnode_black(y)) {
/* Case 4:
* Our sibling is black and has only black
* children. Flip it red and turn parent black.
* This way we gained a black node in our path,
* or we fix it recursively one layer up, which
* will rotate the red sibling as parent. */
rbnode_reparent(s, p, RBNODE_RED);
if (rbnode_black(p))
return p;
rbnode_reparent(p, rbnode_parent(p), RBNODE_BLACK);
return NULL;
}
/* Case 5:
* Left child of our sibling is red, right one is black.
* Rotate on parent so the right child of our sibling is
* now red, and we can fall through to case 6. */
x = y->right;
s->left = y->right;
y->right = s;
p->right = y;
if (x)
rbnode_reparent(x, s, RBNODE_BLACK);
x = s;
s = y;
}
/* Case 6:
* The right child of our sibling is red. Rotate left and flip
* colors, which gains us an additional black node in our path,
* that was previously on our sibling. */
g = rbnode_parent(p);
y = s->left;
p->right = y;
s->left = p;
rbnode_reparent(x, s, RBNODE_BLACK);
if (y)
rbnode_reparent(y, p, rbnode_color(y));
rbnode_reparent(s, g, rbnode_color(p));
rbnode_reparent(p, s, RBNODE_BLACK);
rbtree_reparent(t, g, p, s);
} else /* if (!n || n == p->right) */ { /* same as above, but mirrored */
s = p->left;
if (rbnode_red(s)) {
g = rbnode_parent(p);
x = s->right;
p->left = x;
s->right = p;
rbnode_reparent(x, p, RBNODE_BLACK);
rbnode_reparent(s, g, RBNODE_BLACK);
rbnode_reparent(p, s, RBNODE_RED);
rbtree_reparent(t, g, p, s);
s = x;
}
x = s->left;
if (!x || rbnode_black(x)) {
y = s->right;
if (!y || rbnode_black(y)) {
rbnode_reparent(s, p, RBNODE_RED);
if (rbnode_black(p))
return p;
rbnode_reparent(p, rbnode_parent(p), RBNODE_BLACK);
return NULL;
}
x = y->left;
s->right = y->left;
y->left = s;
p->left = y;
if (x)
rbnode_reparent(x, s, RBNODE_BLACK);
x = s;
s = y;
}
g = rbnode_parent(p);
y = s->right;
p->left = y;
s->right = p;
rbnode_reparent(x, s, RBNODE_BLACK);
if (y)
rbnode_reparent(y, p, rbnode_color(y));
rbnode_reparent(s, g, rbnode_color(p));
rbnode_reparent(p, s, RBNODE_BLACK);
rbtree_reparent(t, g, p, s);
}
return NULL;
}
static inline void rbtree_rebalance(RBTree *t, RBNode *p) {
RBNode *n = NULL;
while (p) {
n = rbtree_rebalance_one(t, p, n);
p = n ? rbnode_parent(n) : NULL;
}
}
void rbtree_remove(RBTree *t, RBNode *n) {
RBNode *p, *s, *gc, *x, *next = NULL;
unsigned long c;
/*
* To remove an interior node from a binary tree, we simply find its
* successor, swap both nodes and then remove the node. Therefore, the
* only interesting case is were the node to be removed has at most one
* child.
* p: parent
* s: successor
* gc: grand-...-child
* x: temporary
* next: next node to rebalance on
*/
if (!n->left) {
/* Case 1:
* We have at most one child, which must be red. We're
* guaranteed to be black then. Replace our node with the child
* (in case it exists), but turn it black.
* If no child exists, we need to rebalance, in case we were
* black as our path now lost a black node. */
p = rbnode_parent(n);
c = rbnode_color(n);
rbtree_reparent(t, p, n, n->right);
if (n->right)
rbnode_reparent(n->right, p, c);
else
next = (c == RBNODE_BLACK) ? p : NULL;
} else if (!n->right) {
/* case 1 mirrored (but n->left guaranteed non-NULL) */
p = rbnode_parent(n);
c = rbnode_color(n);
rbnode_reparent(n->left, p, c);
rbtree_reparent(t, p, n, n->left);
} else {
/* Case 2:
* We're an interior node. Find our successor and swap it with
* our node. Then remove our node. For performance reasons we
* don't perform the full swap, but skip links that are about to
* be removed, anyway. */
s = n->right;
if (!s->left) {
/* right child is next, no need to touch grandchild */
p = s;
gc = s->right;
} else {
/* find successor and swap partially */
s = rbnode_leftmost(s);
p = rbnode_parent(s);
gc = s->right;
p->left = s->right;
s->right = n->right;
rbnode_reparent(n->right, s, rbnode_color(n->right));
}
/* node is partially swapped, now remove as in case 1 */
s->left = n->left;
rbnode_reparent(n->left, s, rbnode_color(n->left));
x = rbnode_parent(n);
c = rbnode_color(n);
rbtree_reparent(t, x, n, s);
if (gc) {
rbnode_reparent(s, x, c);
rbnode_reparent(gc, p, RBNODE_BLACK);
} else {
next = rbnode_black(s) ? p : NULL;
rbnode_reparent(s, x, c);
}
}
if (next)
rbtree_rebalance(t, next);
}

107
src/shared-rbtree.h Normal file
View File

@@ -0,0 +1,107 @@
#pragma once
/***
This file is part of ratbagd.
Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
***/
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#ifdef RBTREE_DEBUG
# include <assert.h>
# define rbtree_assert(_x) assert(_x)
#else
# define rbtree_assert(_x)
#endif
typedef struct RBTree RBTree;
typedef struct RBNode RBNode;
enum {
RBNODE_RED = 0,
RBNODE_BLACK = 1,
};
struct RBTree {
RBNode *root;
};
struct RBNode {
RBNode *__parent_and_color;
RBNode *left;
RBNode *right;
};
#define rbnode_of(_ptr, _type, _member) \
__extension__ ({ \
const typeof( ((_type*)0)->_member ) *__ptr = (_ptr); \
__ptr ? (_type*)( (char*)__ptr - offsetof(_type, _member) ) : NULL; \
})
#define RBNODE_INIT(var) ((RBNode){ .__parent_and_color = (&var) })
static inline RBNode *rbnode_init(RBNode *n) {
*n = RBNODE_INIT(*n);
return n;
}
static inline RBNode *rbnode_parent(RBNode *n) {
return (RBNode*)((unsigned long)n->__parent_and_color & ~1UL);
}
static inline int rbnode_linked(RBNode *n) {
return n && n->__parent_and_color != n;
}
static inline unsigned long rbnode_color(RBNode *n) {
return (unsigned long)n->__parent_and_color & 1UL;
}
static inline int rbnode_red(RBNode *n) {
return rbnode_color(n) == RBNODE_RED;
}
static inline int rbnode_black(RBNode *n) {
return rbnode_color(n) == RBNODE_BLACK;
}
RBNode *rbnode_leftmost(RBNode *n);
RBNode *rbnode_rightmost(RBNode *n);
RBNode *rbtree_first(RBTree *t);
RBNode *rbtree_last(RBTree *t);
RBNode *rbnode_next(RBNode *n);
RBNode *rbnode_prev(RBNode *n);
void rbtree_add(RBTree *t, RBNode *p, RBNode **l, RBNode *n);
void rbtree_remove(RBTree *t, RBNode *n);
#ifdef __cplusplus
}
#endif

View File

@@ -31,6 +31,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include "libratbag.h"
@@ -162,6 +163,9 @@ int main(void)
Suite *s;
SRunner *sr;
bool using_valgrind;
const struct rlimit corelimit = { 0, 0 };
setrlimit(RLIMIT_CORE, &corelimit);
/* when running under valgrind we're using nofork mode, so a
* signal raised by a test will fail in valgrind */

View File

@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <sys/resource.h>
#include "libratbag.h"
#include "libratbag-test.h"
@@ -488,7 +489,7 @@ START_TEST(device_freed_before_profile)
is_active = ratbag_profile_is_active(p);
ck_assert_int_eq(is_active, 1);
p = ratbag_profile_unref(p);
ratbag_profile_unref(p);
ratbag_unref(r);
ck_assert_int_eq(device_freed_count, 1);
}
@@ -680,7 +681,7 @@ START_TEST(device_buttons)
struct ratbag_test_device td = sane_device;
td.num_buttons = 10;
td.profiles[0].buttons[8].type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
td.profiles[0].buttons[8].action_type = RATBAG_BUTTON_ACTION_TYPE_MACRO;
td.destroyed_data = &device_freed_count;
@@ -932,6 +933,9 @@ int main(void)
int nfailed;
Suite *s;
SRunner *sr;
const struct rlimit corelimit = { 0, 0 };
setrlimit(RLIMIT_CORE, &corelimit);
s = test_context_suite();
sr = srunner_create(s);

View File

@@ -25,6 +25,7 @@
#include <check.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
#include "libratbag-util.h"
@@ -166,6 +167,9 @@ int main(void)
int nfailed;
Suite *s;
SRunner *sr;
const struct rlimit corelimit = { 0, 0 };
setrlimit(RLIMIT_CORE, &corelimit);
s = test_context_suite();
sr = srunner_create(s);

View File

@@ -98,7 +98,7 @@ main(int argc, char **argv)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp10_device_new(&base, HIDPP_WIRED_DEVICE_IDX, HIDPP10_PROFILE_UNKNOWN);
dev = hidpp10_device_new(&base, HIDPP_WIRED_DEVICE_IDX, HIDPP10_PROFILE_UNKNOWN, 5);
if (argc == 2)
rc = dump_all_pages(dev);

View File

@@ -21,7 +21,8 @@
* DEALINGS IN THE SOFTWARE.
*/
#define _GNU_SOURCE
#include "config.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>

67
tools/merge_ratbagd.py Executable file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
#
# vim: set expandtab shiftwidth=4 tabstop=4:
#
# Copyright 2017 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import argparse
import os
import stat
import sys
def print_ratbagctl(ratbagctl_path, ratbagd_path, version_string):
with open(ratbagctl_path, 'r') as ratbagctl, open(ratbagd_path, 'r') as ratbagd:
for l in ratbagctl.readlines():
if l.startswith("from ratbagd import "):
headers = True
for r in ratbagd.readlines():
if not r.startswith('#') and r.strip():
headers = False
if not headers:
print(r.rstrip('\n'))
else:
if '@version@' in l:
l = l.replace('@version@', version_string)
print(l.rstrip('\n'))
def main(argv):
parser = argparse.ArgumentParser(description="merge ratbagd.py into ratbagctl")
parser.add_argument("ratbagctl", action='store')
parser.add_argument("ratbagd", action='store')
parser.add_argument("--output", action="store")
parser.add_argument("--version", action="store", default="git_master")
ns = parser.parse_args(sys.argv[1:])
if ns.output:
ns.output_file = open(ns.output, 'w')
st = os.stat(ns.output)
os.chmod(ns.output, st.st_mode | stat.S_IEXEC)
sys.stdout = ns.output_file
print_ratbagctl(ns.ratbagctl, ns.ratbagd, ns.version)
try:
ns.output_file.close()
except AttributeError:
pass
if __name__ == "__main__":
main(sys.argv[1:])

View File

@@ -106,8 +106,8 @@ usage(void)
"Profile Commands:\n"
" profile active get Print the currently active profile\n"
" profile active set N Set profile N as to the active profile\n"
" profile enable N Enable profile N\n"
" profile disable N Disable profile N\n"
" profile N enable Enable profile N\n"
" profile N disable Disable profile N\n"
" profile N {COMMAND} Use profile N for COMMAND\n"
"\n"
"Resolution Commands\n"
@@ -432,6 +432,8 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
for (int i = 0; i < num_profiles; i++) {
int dpi, rate;
struct ratbag_resolution *res;
profile = ratbag_device_get_profile(device, i);
if (!profile)
continue;
@@ -439,10 +441,18 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
printf(" Profile %d (%s)%s\n", i,
ratbag_profile_is_enabled(profile) ? "enabled" : "disabled",
ratbag_profile_is_active(profile) ? " (active)" : "");
printf(" Resolutions:\n");
for (unsigned int j = 0; j < ratbag_profile_get_num_resolutions(profile); j++) {
struct ratbag_resolution *res;
if (!ratbag_profile_is_enabled(profile))
continue;
printf(" Resolutions:\n");
res = ratbag_profile_get_resolution(profile, 0);
printf(" Range: [%d, %d]\n",
ratbag_resolution_get_dpi_minimum(res),
ratbag_resolution_get_dpi_maximum(res));
ratbag_resolution_unref(res);
for (unsigned int j = 0; j < ratbag_profile_get_num_resolutions(profile); j++) {
res = ratbag_profile_get_resolution(profile, j);
dpi = ratbag_resolution_get_dpi(res);
rate = ratbag_resolution_get_report_rate(res);
@@ -473,13 +483,13 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd,
printf(" Button: %d type %s is mapped to '%s'\n",
b, button_type_to_str(type), action);
free(action);
button = ratbag_button_unref(button);
ratbag_button_unref(button);
}
for (l = 0; l < num_leds; l++) {
led = ratbag_profile_get_led(profile, l);
ratbag_printf_led(led, " LED: %d ", l);
led = ratbag_led_unref(led);
ratbag_led_unref(led);
}
ratbag_profile_unref(profile);
@@ -533,8 +543,8 @@ ratbag_cmd_switch_etekcity(const struct ratbag_cmd *cmd,
commit = 2;
}
button_6 = ratbag_button_unref(button_6);
button_7 = ratbag_button_unref(button_7);
ratbag_button_unref(button_6);
ratbag_button_unref(button_7);
printf("Switched the current profile of '%s' to %sreport the volume keys\n",
ratbag_device_get_name(device),
@@ -666,6 +676,9 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd,
argc -= 3;
argv += 3;
(void)argc;
(void)argv;
if (streq(action_str, "button")) {
action_type = RATBAG_BUTTON_ACTION_TYPE_BUTTON;
btnkey = atoi(action_arg);
@@ -759,7 +772,7 @@ ratbag_cmd_change_button(const struct ratbag_cmd *cmd,
}
out:
button = ratbag_button_unref(button);
ratbag_button_unref(button);
return rc;
}
@@ -828,10 +841,29 @@ ratbag_cmd_resolution_active_set(const struct ratbag_cmd *cmd,
struct ratbag_cmd_options *options,
int argc, char **argv)
{
struct ratbag_profile *profile = options->profile;
struct ratbag_resolution *resolution;
int rc;
int num_resolutions, index;
int rc = SUCCESS;
index = atoi(argv[0]);
argc--;
argv++;
num_resolutions = ratbag_profile_get_num_resolutions(profile);
if (index >= num_resolutions) {
error("'%d' is not a valid resolution\n", index);
rc = ERR_USAGE;
goto out;
}
resolution = ratbag_profile_get_resolution(profile, index);
if (ratbag_resolution_is_active(resolution)) {
rc = SUCCESS;
goto out;
}
resolution = options->resolution;
rc = ratbag_resolution_set_active(resolution);
if (rc != 0) {
@@ -839,7 +871,10 @@ ratbag_cmd_resolution_active_set(const struct ratbag_cmd *cmd,
return ERR_DEVICE;
}
return SUCCESS;
out:
ratbag_resolution_unref(resolution);
return rc;
}
static const struct ratbag_cmd cmd_resolution_active_set = {
@@ -1862,7 +1897,7 @@ ratbag_cmd_profile_active_set(const struct ratbag_cmd *cmd,
}
out:
profile = ratbag_profile_unref(profile);
ratbag_profile_unref(profile);
return rc;
}

10
tools/ratbag-git-sha.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
GIT_DIR="$MESON_SOURCE_ROOT/.git"
export GIT_DIR
git log --format="format:%h" -1 2>/dev/null
if test $? -ne 0; then
echo "unknown"
fi

75
tools/ratbagctl.1 Normal file
View File

@@ -0,0 +1,75 @@
.TH ratbagctl 1 "Apr 13, 2016" ratbagctl
.SH NAME
ratbagctl \- inspect and modify configurable mice
.SH SYNOPSIS
.B ratbagctl
.RB [ \-h ]
.RB [ \-V ]
.br
.B ratbagctl list-devices
.br
.B ratbagctl show-device
.RI < device >
.br
.B ratbagctl show-profile
.RI < device "> <" profile >
.br
.B ratbagctl show-resolution
.RI < device "> <" profile "> <" resolution >
.br
.B ratbagctl show-button
.RI < device "> <" profile "> <" button >
.SH DESCRIPTION
.SS Common options
.TP
.BR \-h
displays a short help message (it can be used with any form of the
.B ratbagctl
command).
.TP
.BR \-V
displays the version of
.B ratbagctl
and exits.
.SS Listing devices
.TP
.B list-devices
lists all identified devices on the system.
.SS Displaying a device
.TP
.BR show-device " <" \fIdevice\fP >
displays the device information for the given
.I device
(as identified by
.BR list-devices ).
.SS Displaying profiles
.TP
.IR \fBshow-profile\fP " <" device "> <" profile >
displays the profile information for the given
.I device
and
.IR "profile index" .
.SS Displaying resolution information
.TP
.IR \fBshow-resolution\fP " <" device "> <" profile "> <" resolution >
displays the resolution information for the given
.IR device ,
.IR "profile index" ,
and
.IR "resolution index" .
.SS Displaying button information
.TP
.IR \fBshow-button\fP " <" device "> <" profile "> <" button >
displays the resolution information for the given
.IR device ,
.IR "profile index" ,
and
.IR "button index" .
.SH SEE ALSO
.BR ratbagd (8)
.SH AUTHORS
.B ratbagctl
was written by David Herrmann, Peter Hutterer and Benjamin Tissoires.
.PP
This manual page was written by Stephen Kitt <skitt@debian.org> for
the Debian GNU/Linux system (but may be used by others).

76
tools/ratbagctl.devel.in Executable file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
#
# vim: set expandtab shiftwidth=4 tabstop=4:
#
# This file is part of libratbag.
#
# Copyright 2017 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import os
import toolbox
import signal
import sys
def main(argv):
if not os.geteuid() == 0:
sys.exit('Script must be run as root')
if not argv:
argv = ["list"]
ratbagd_process = toolbox.start_ratbagd()
if ratbagd_process is None:
sys.exit("Failed to start or connect to ratbagd")
ratbagd = toolbox.open_ratbagd()
parser = toolbox.get_parser()
parser.want_keepalive = True
cmd = None
try:
cmd = parser.parse(argv)
if cmd.help:
parser.print_help()
else:
try:
f = cmd.func
except AttributeError:
parser.print_help()
return
else:
f(ratbagd, cmd)
finally:
try:
if cmd.keepalive:
print('\nexport RATBAGCTL_DEVEL="{}"\n'.format(os.environ['RATBAGCTL_DEVEL']))
signal.pause()
except KeyboardInterrupt:
pass
except AttributeError: # in case the parsing failed and cmd is None
pass
toolbox.terminate_ratbagd(ratbagd_process)
if __name__ == "__main__":
main(sys.argv[1:])

1478
tools/ratbagctl.in Executable file

File diff suppressed because it is too large Load Diff

560
tools/ratbagctl.test.in Executable file
View File

@@ -0,0 +1,560 @@
#!/usr/bin/env python3
#
# vim: set expandtab shiftwidth=4 tabstop=4:
#
# This file is part of libratbag.
#
# Copyright 2017 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import argparse
import io
import os
import resource
import subprocess
import sys
import toolbox
import unittest
run_ratbagctl_in_subprocess = False
class TestRatbagCtl(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(TestRatbagCtl, cls).setUpClass()
cls.reset_test_device()
@classmethod
def run_ratbagctl_subprocess(cls, params):
ratbagctl = subprocess.Popen(" ".join([toolbox.RATBAGCTL_PATH, params]),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
env={"RATBAGCTL_DEVEL": "org.freedesktop.ratbag_devel1_@ratbagd_sha@"})
(stdout, stderr) = ratbagctl.communicate()
return (ratbagctl.returncode,
stdout.decode('ascii').rstrip('\n'),
stderr.decode('ascii').rstrip('\n'))
@classmethod
def run_ratbagctl_fast(cls, params):
global parser, ratbagd
stdout = sys.stdout
stderr = sys.stderr
returncode = 0
sys.stdout = io.StringIO()
sys.stderr = io.StringIO()
try:
cmd = parser.parse(params.split())
cmd.func(ratbagd, cmd)
except SystemExit as e:
returncode = e.code
output = sys.stdout.getvalue()
error = sys.stderr.getvalue()
sys.stdout = stdout
sys.stderr = stderr
return returncode, output.rstrip('\n'), error.rstrip('\n')
@classmethod
def run_ratbagctl(cls, params):
if run_ratbagctl_in_subprocess:
return cls.run_ratbagctl_subprocess(params)
return cls.run_ratbagctl_fast(params)
@classmethod
def reset_test_device(cls):
global ratbagd
ratbagd._dbus_call("ResetTestDevice", "")
def launch_good_test(self, params):
returncode, stdout, stderr = self.run_ratbagctl(params)
self.assertEqual(returncode, 0)
return stdout
def launch_fail_test(self, params):
returncode, stdout, stderr = self.run_ratbagctl(params)
self.assertNotEqual(returncode, 0)
return stdout
@classmethod
def setProfile(cls, profile):
cls.run_ratbagctl("Profile active set {} test_device".format(profile))
class TestRatbagCtlList(TestRatbagCtl):
def test_list(self):
r = self.launch_good_test("list")
self.assertIn('test_device', r)
self.launch_fail_test("list test_device")
class TestRatbagCtlInfo(TestRatbagCtl):
def test_info(self):
self.launch_good_test("info test_device")
self.launch_fail_test("info test_device X")
self.launch_fail_test("info X")
class TestRatbgagCtlProfile(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlProfile, cls).setUpClass()
cls.setProfile(0)
def test_profile_active_get(self):
command = "profile active get"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 0)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
def test_profile_active_set(self):
command = "profile active set"
r = self.launch_good_test(command + " 1 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("profile active get test_device")
self.assertEqual(int(r), 1)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 1 test_device X")
def test_profile_n(self):
r0 = self.launch_good_test("Profile 0 get test_device")
r1 = self.launch_good_test("Profile 1 get test_device")
self.assertNotEqual(r0, r1)
self.launch_fail_test("Profile 0 get")
self.launch_fail_test("Profile 0 test_device")
self.launch_fail_test("Profile 0 get test_device X")
self.launch_fail_test("Profile 10 get test_device")
def test_profile_enable(self):
r = self.launch_good_test("profile 0 get test_device")
self.assertNotIn('disabled', r)
r = self.launch_good_test("profile 3 get test_device")
self.assertIn('disabled', r)
self.launch_good_test("profile 3 enable test_device")
r = self.launch_good_test("profile 3 get test_device")
self.assertNotIn('Profile 3: (disabled)', r)
self.launch_fail_test("profile enable")
self.launch_fail_test("profile X enable test_device")
self.launch_fail_test("profile 1 enable test_device X")
self.launch_fail_test("profile 10 enable test_device")
def test_profile_disable(self):
r = self.launch_good_test("profile 2 get test_device")
self.assertNotIn('disabled', r)
self.launch_good_test("profile 2 disable test_device")
r = self.launch_good_test("profile 2 get test_device")
self.assertEqual('Profile 2: (disabled)', r)
self.launch_fail_test("profile disable")
self.launch_fail_test("profile X disable test_device")
self.launch_fail_test("profile 1 disable test_device X")
self.launch_fail_test("profile 10 disable test_device")
class TestRatbgagCtlResolution(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlResolution, cls).setUpClass()
cls.setProfile(1)
def test_resolution_active_get(self):
command = "Resolution active get"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 2)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 10 test_device")
self.launch_fail_test(command + " test_device x")
def test_resolution_active_set(self):
command = "Resolution active set"
r = self.launch_good_test("Resolution active get test_device")
self.assertEqual(int(r), 2)
r = self.launch_good_test(command + " 0 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("Resolution active get test_device")
self.assertEqual(int(r), 0)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 1 test_device X")
def test_resolution_n_get(self):
r = self.launch_good_test("Resolution 1 get test_device")
self.assertEqual(r, "1: 1200x1300dpi @ 2000Hz (default)")
self.launch_fail_test("Resolution 10 get test_device")
self.launch_fail_test("Resolution 1 get test_device X")
self.launch_fail_test("Resolution 1 get X")
def test_profile_resolution(self):
r = self.launch_good_test("Profile 2 Resolution 2 get test_device")
self.assertEqual(r, "2: 2300x2400dpi @ 3000Hz")
def test_resolution_default_get(self):
command = "Resolution default get"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 1)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 10 test_device")
self.launch_fail_test(command + " test_device x")
def test_resolution_default_set(self):
command = "Resolution default set"
self.launch_good_test(command + " 2 test_device")
r = self.launch_good_test("Resolution default get test_device")
self.assertEqual(int(r), 2)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 1 test_device X")
# Reset for other tests
self.launch_good_test(command + " 1 test_device")
class TestRatbgagCtlDPI(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlDPI, cls).setUpClass()
cls.setProfile(0)
def test_dpi_get(self):
command = "DPI get"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 200)
self.setProfile(1)
r = self.launch_good_test(command + " test_device")
self.assertEqual(r, "1300x1400dpi")
self.launch_fail_test(command)
self.launch_fail_test(command + " 1 test_device")
self.launch_fail_test(command + " test_device X")
def test_dpi_set(self):
command = "DPI set"
self.setProfile(0)
r = self.launch_good_test("DPI get test_device")
res = int(r) + 50
r = self.launch_good_test(command + " {} test_device".format(res))
self.assertEqual(r, '')
r = self.launch_good_test("DPI get test_device")
self.assertEqual(int(r), res)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 100 test_device X")
def test_dpi_set_xy(self):
command = "DPI set"
self.setProfile(2)
r = self.launch_good_test("DPI get test_device")
self.assertEqual(r, "2100x2200dpi")
self.launch_good_test(command + " 1350x1450 test_device")
r = self.launch_good_test("DPI get test_device")
self.assertEqual(r, "1350x1450dpi")
self.launch_good_test(command + " 2350x2450dpi test_device")
r = self.launch_good_test("DPI get test_device")
self.assertEqual(r, "2350x2450dpi")
self.launch_good_test(command + " 2350 test_device")
r = self.launch_good_test("DPI get test_device")
self.assertEqual(r, "2350x2350dpi")
self.launch_fail_test(command + " 2350dpi test_device")
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 100 test_device X")
def test_prefix_dpi(self):
self.setProfile(0)
r = self.launch_good_test("Profile 1 DPI get test_device")
self.assertEqual(r, "1300x1400dpi")
r = self.launch_good_test("Profile 1 Resolution 1 DPI get test_device")
self.assertEqual(r, "1200x1300dpi")
r = self.launch_good_test("Resolution 2 DPI get test_device")
self.assertEqual(int(r), 300)
self.launch_fail_test("Profile 1 Profile 1 DPI get test_device")
self.launch_fail_test("Profile 1 Resolution 1 Resolution 2 DPI get test_device")
class TestRatbgagCtlReportRate(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlReportRate, cls).setUpClass()
cls.setProfile(0)
def test_rate_get(self):
command = "rate get"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 1000)
self.launch_fail_test(command)
self.launch_fail_test(command + " 1 test_device")
self.launch_fail_test(command + " test_device X")
def test_rate_set(self):
command = "rate set"
r = self.launch_good_test("rate get test_device")
res = int(r) + 500
r = self.launch_good_test(command + " {} test_device".format(res))
self.assertEqual(r, '')
r = self.launch_good_test("rate get test_device")
self.assertEqual(int(r), res)
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 100 test_device X")
def test_prefix_rate(self):
r = self.launch_good_test("Profile 1 rate get test_device")
self.assertEqual(int(r), 2000)
r = self.launch_good_test("Profile 1 Resolution 1 rate get test_device")
self.assertEqual(int(r), 2000)
r = self.launch_good_test("Resolution 2 rate get test_device")
self.assertEqual(int(r), 1000)
self.launch_fail_test("Profile 1 Profile 1 rate get test_device")
self.launch_fail_test("Profile 1 Resolution 1 Resolution 2 rate get test_device")
class TestRatbgagCtlButton(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlButton, cls).setUpClass()
cls.setProfile(0)
def test_button_count(self):
command = "button count"
r = self.launch_good_test(command + " test_device")
self.assertEqual(int(r), 4)
self.launch_fail_test(command)
self.launch_fail_test(command + " 1 test_device")
self.launch_fail_test(command + " test_device X")
def test_button_n_get(self):
self.setProfile(0)
r = self.launch_good_test("button 0 get test_device")
self.assertEqual(r, "Button: 0 type left is mapped to 'button 0'")
r = self.launch_good_test("button 1 get test_device")
self.assertEqual(r, "Button: 1 type middle is mapped to 'KEY_3'")
r = self.launch_good_test("button 2 get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to 'profile-cycle-up'")
r = self.launch_good_test("button 3 get test_device")
self.assertEqual(r, "Button: 3 type unknown is mapped to macro '+KEY_B -KEY_B t300'")
self.launch_fail_test("button 1 get 10 test_device")
self.launch_fail_test("button 10 get test_device")
self.launch_fail_test("button 1 get test_device X")
def test_button_n_action_get(self):
self.setProfile(0)
r = self.launch_good_test("button 0 action get test_device")
self.assertEqual(r, "Button: 0 type left is mapped to 'button 0'")
self.launch_fail_test("button 1 action get 10 test_device")
self.launch_fail_test("button 10 action get test_device")
self.launch_fail_test("button 1 action get test_device X")
def test_button_n_action_set_button(self):
self.setProfile(2)
command = "button 2 action set button"
r = self.launch_good_test("button 2 action get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to 'button 2'")
r = self.launch_good_test(command + " 1 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("button 2 action get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to 'button 1'")
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 100 test_device X")
def test_button_n_action_set_special(self):
self.setProfile(2)
command = "button 0 action set special "
r = self.launch_good_test("button 0 action get test_device")
self.assertEqual(r, "Button: 0 type left is mapped to 'profile-cycle-up'")
r = self.launch_good_test(command + " second-mode test_device")
self.assertEqual(r, '')
r = self.launch_good_test("button 0 action get test_device")
self.assertEqual(r, "Button: 0 type left is mapped to 'second-mode'")
self.launch_fail_test(command)
self.launch_fail_test(command + " X test_device")
self.launch_fail_test(command + " 100 test_device X")
def test_button_n_action_set_macro(self):
command = "button 2 action set macro "
self.launch_good_test(command + '+KEY_B KEY_A -KEY_B KEY_C test_device')
r = self.launch_good_test("button 2 get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to macro '+KEY_B +KEY_A -KEY_A -KEY_B +KEY_C -KEY_C'")
self.launch_good_test(command + 't100 t200 test_device')
r = self.launch_good_test("button 2 get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to macro 't100 t200'")
self.launch_good_test(command + 'KeY_z test_device')
r = self.launch_good_test("button 2 get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to macro '+KEY_Z -KEY_Z'")
self.launch_good_test(command + ' test_device')
r = self.launch_good_test("button 2 get test_device")
self.assertEqual(r, "Button: 2 type right is mapped to macro ''")
self.launch_fail_test(command)
self.launch_fail_test(command + " KEY_A test_device X")
def test_prefix_button(self):
r = self.launch_good_test("Profile 2 Button 3 get test_device")
self.assertEqual(r, "Button: 3 type unknown is mapped to 'button 3'")
self.launch_fail_test("Profile 2 Profile 2 Button 3 get test_device")
self.launch_fail_test("Profile 2 Resolution 2 Button 3 get test_device")
class TestRatbgagCtlLED(TestRatbagCtl):
@classmethod
def setUpClass(cls):
super(TestRatbgagCtlLED, cls).setUpClass()
cls.setProfile(0)
def test_led_n_get(self):
self.setProfile(0)
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: off")
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: on, color: ff0000")
r = self.launch_good_test("led 2 get test_device")
self.assertEqual(r, "LED: 2 type: logo, mode: cycle, rate: 3, brightness: 40")
self.launch_fail_test("led 0 get 10 test_device")
self.launch_fail_test("led 10 get test_device")
self.launch_fail_test("led 0 get test_device X")
def test_led_n_set_mode(self):
self.setProfile(0)
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: off")
r = self.launch_good_test("led 0 set mode cycle test_device")
self.assertEqual(r, '')
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: cycle, rate: 1, brightness: 20")
self.launch_fail_test("led 0 set mode bicycle test_device")
self.launch_fail_test("led 0 set mode test_device")
self.launch_fail_test("led 0 set mode cycle test_device X")
self.launch_fail_test("led 0 set mode cycle X test_device")
def test_led_n_set_color(self):
self.setProfile(0)
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: on, color: ff0000")
r = self.launch_good_test("led 1 set color 00ff00 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: on, color: 00ff00")
r = self.launch_good_test("led 1 set color 0x0000ff test_device")
self.assertEqual(r, '')
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: on, color: 0000ff")
self.launch_fail_test("led 1 set color g0ff00 test_device")
self.launch_fail_test("led 1 set color test_device")
self.launch_fail_test("led 1 set color 00ff00 test_device X")
self.launch_fail_test("led 1 set color 00ff00 X test_device")
def test_led_n_set_rate(self):
self.setProfile(0)
r = self.launch_good_test("led 2 get test_device")
self.assertEqual(r, "LED: 2 type: logo, mode: cycle, rate: 3, brightness: 40")
r = self.launch_good_test("led 2 set rate 100 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("led 2 get test_device")
self.assertEqual(r, "LED: 2 type: logo, mode: cycle, rate: 100, brightness: 40")
self.launch_fail_test("led 2 set rate this_is_not_an_int test_device")
self.launch_fail_test("led 2 set rate test_device")
self.launch_fail_test("led 2 set rate 100 test_device X")
self.launch_fail_test("led 2 set rate 100 X test_device")
def test_led_n_set_brightness(self):
self.setProfile(2)
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: cycle, rate: 3, brightness: 40")
r = self.launch_good_test("led 1 set brightness 100 test_device")
self.assertEqual(r, '')
r = self.launch_good_test("led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: cycle, rate: 3, brightness: 100")
self.launch_fail_test("led 1 set brightness this_is_not_an_int test_device")
self.launch_fail_test("led 1 set brightness test_device")
self.launch_fail_test("led 1 set brightness 100 test_device X")
self.launch_fail_test("led 1 set brightness 100 X test_device")
self.launch_fail_test("led 1 set brightness this_is_not_an_int test_device")
self.launch_fail_test("led 1 set brightness 256 test_device")
self.launch_fail_test("led 1 set brightness -10 test_device")
def test_led_n_set_combination(self):
self.setProfile(2)
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: on, color: ff0000")
r = self.launch_good_test("led 0 set mode cycle brightness 100 test_device")
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: cycle, rate: 1, brightness: 100")
r = self.launch_good_test("led 0 set mode cycle rate 100 brightness 255 test_device")
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: cycle, rate: 100, brightness: 255")
r = self.launch_good_test("led 0 set mode on color 00ff00 test_device")
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: on, color: 00ff00")
r = self.launch_good_test("led 0 set rate 100 brightness 200 mode cycle test_device")
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: cycle, rate: 100, brightness: 200")
r = self.launch_good_test("led 0 set rate 100 brightness 200 mode cycle brightness 100 test_device")
r = self.launch_good_test("led 0 get test_device")
self.assertEqual(r, "LED: 0 type: logo, mode: cycle, rate: 100, brightness: 100")
self.launch_fail_test("led 0 set brightness 10 mode bicycle test_device")
def test_prefix_led(self):
self.setProfile(2)
r = self.launch_good_test("Profile 1 Led 1 get test_device")
self.assertEqual(r, "LED: 1 type: logo, mode: off")
self.launch_fail_test("Profile 1 Profile 2 Led 1 get test_device")
self.launch_fail_test("Profile 1 Resolution 2 Led 1 get test_device")
def setUpModule():
global ratbagd_process, ratbagd, parser
ratbagd_process = toolbox.start_ratbagd()
ratbagd = toolbox.open_ratbagd(ratbagd_process)
assert ratbagd is not None
parser = toolbox.get_parser()
def tearDownModule():
global ratbagd_process
toolbox.terminate_ratbagd(ratbagd_process)
def parse(input_string):
global run_ratbagctl_in_subprocess
parser_test = argparse.ArgumentParser(description="Testsuite for ratbagd/ratbagctl", add_help=False)
parser_test.add_argument("--subprocess", action='store_true', default=False)
ns, rest = parser_test.parse_known_args(input_string)
run_ratbagctl_in_subprocess = ns.subprocess
return rest
def main(argv):
if not os.geteuid() == 0:
sys.exit('Script must be run as root')
resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
args = parse(argv)
unittest.main(argv=[sys.argv[0], *args])
if __name__ == "__main__":
main(sys.argv[1:])

670
tools/ratbagd.py Normal file
View File

@@ -0,0 +1,670 @@
# vim: set expandtab shiftwidth=4 tabstop=4:
#
# Copyright 2016 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import os
import sys
from enum import IntEnum
from gi.repository import Gio, GLib, GObject
class RatbagErrorCode(IntEnum):
RATBAG_SUCCESS = 0
"""An error occured on the device. Either the device is not a libratbag
device or communication with the device failed."""
RATBAG_ERROR_DEVICE = -1000
"""Insufficient capabilities. This error occurs when a requested change is
beyond the device's capabilities."""
RATBAG_ERROR_CAPABILITY = -1001
"""Invalid value or value range. The provided value or value range is
outside of the legal or supported range."""
RATBAG_ERROR_VALUE = -1002
"""A low-level system error has occured, e.g. a failure to access files
that should be there. This error is usually unrecoverable and libratbag will
print a log message with details about the error."""
RATBAG_ERROR_SYSTEM = -1003
"""Implementation bug, either in libratbag or in the caller. This error is
usually unrecoverable and libratbag will print a log message with details
about the error."""
RATBAG_ERROR_IMPLEMENTATION = -1004
class RatbagdDBusUnavailable(Exception):
"""Signals DBus is unavailable or the ratbagd daemon is not available."""
pass
class RatbagdDBusTimeout(Exception):
"""Signals that a timeout occurred during a DBus method call."""
pass
class RatbagError(Exception):
"""A common base exception to catch any ratbag exception."""
pass
class RatbagErrorDevice(RatbagError):
"""An exception corresponding to RatbagErrorCode.RATBAG_ERROR_DEVICE."""
pass
class RatbagErrorCapability(RatbagError):
"""An exception corresponding to RatbagErrorCode.RATBAG_ERROR_CAPABILITY."""
pass
class RatbagErrorValue(RatbagError):
"""An exception corresponding to RatbagErrorCode.RATBAG_ERROR_Value."""
pass
class RatbagErrorSystem(RatbagError):
"""An exception corresponding to RatbagErrorCode.RATBAG_ERROR_System."""
pass
class RatbagErrorImplementation(RatbagError):
"""An exception corresponding to RatbagErrorCode.RATBAG_ERROR_IMPLEMENTATION."""
pass
"""A table mapping RatbagErrorCode values to RatbagError* exceptions."""
EXCEPTION_TABLE = {
RatbagErrorCode.RATBAG_ERROR_DEVICE: RatbagErrorDevice,
RatbagErrorCode.RATBAG_ERROR_CAPABILITY: RatbagErrorCapability,
RatbagErrorCode.RATBAG_ERROR_VALUE: RatbagErrorValue,
RatbagErrorCode.RATBAG_ERROR_SYSTEM: RatbagErrorSystem,
RatbagErrorCode.RATBAG_ERROR_IMPLEMENTATION: RatbagErrorImplementation
}
class _RatbagdDBus(GObject.GObject):
_dbus = None
def __init__(self, interface, object_path):
GObject.GObject.__init__(self)
if _RatbagdDBus._dbus is None:
try:
_RatbagdDBus._dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
except GLib.Error as e:
raise RatbagdDBusUnavailable(e.message)
ratbag1 = "org.freedesktop.ratbag1"
if os.environ.get('RATBAGCTL_DEVEL'):
ratbag1 = os.environ['RATBAGCTL_DEVEL']
if object_path is None:
object_path = "/" + ratbag1.replace('.', '/')
self._object_path = object_path
self._interface = "{}.{}".format(ratbag1, interface)
try:
self._proxy = Gio.DBusProxy.new_sync(_RatbagdDBus._dbus,
Gio.DBusProxyFlags.NONE,
None,
ratbag1,
object_path,
self._interface,
None)
except GLib.Error as e:
raise RatbagdDBusUnavailable(e.message)
if self._proxy.get_name_owner() is None:
raise RatbagdDBusUnavailable("No one currently owns {}".format(ratbag1))
def _get_dbus_property(self, property):
# Retrieves a cached property from the bus, or None.
p = self._proxy.get_cached_property(property)
if p is not None:
return p.unpack()
return p
def _set_dbus_property(self, property, type, value, readwrite=True):
# Sets a cached property on the bus.
# Take our real value and wrap it into a variant. To call
# org.freedesktop.DBus.Properties.Set we need to wrap that again
# into a (ssv), where v is our value's variant.
# args to .Set are "interface name", "function name", value-variant
val = GLib.Variant("{}".format(type), value)
if readwrite:
pval = GLib.Variant("(ssv)".format(type), (self._interface, property, val))
self._proxy.call_sync("org.freedesktop.DBus.Properties.Set",
pval, Gio.DBusCallFlags.NO_AUTO_START,
500, None)
# This is our local copy, so we don't have to wait for the async
# update
self._proxy.set_cached_property(property, val)
def _dbus_call(self, method, type, *value):
# Calls a method synchronously on the bus, using the given method name,
# type signature and values.
#
# It the result is valid, it is returned. Invalid results raise the
# appropriate RatbagError* or RatbagdDBus* exception, or GLib.Error if
# it is an unexpected exception that probably shouldn't be passed up to
# the UI.
val = GLib.Variant("({})".format(type), value)
try:
res = self._proxy.call_sync(method, val,
Gio.DBusCallFlags.NO_AUTO_START,
500, None)
global EXCEPTION_TABLE
if res in EXCEPTION_TABLE:
raise EXCEPTION_TABLE[res]
return res.unpack()[0] # Result is always a tuple
except GLib.Error as e:
if e.code == Gio.IOErrorEnum.TIMED_OUT:
raise RatbagdDBusTimeout(e.message)
else:
# Unrecognized error code; print the message to stderr and raise
# the GLib.Error.
print(e.message, file=sys.stderr)
raise
def __eq__(self, other):
return other and self._object_path == other._object_path
class Ratbagd(_RatbagdDBus):
"""The ratbagd top-level object. Provides a list of devices available
through ratbagd; actual interaction with the devices is via the
RatbagdDevice, RatbagdProfile, RatbagdResolution and RatbagdButton objects.
Throws RatbagdDBusUnavailable when the DBus service is not available.
"""
def __init__(self):
_RatbagdDBus.__init__(self, "Manager", None)
@GObject.Property
def devices(self):
"""A list of RatbagdDevice objects supported by ratbagd."""
devices = []
result = self._get_dbus_property("Devices")
if result is not None:
devices = [RatbagdDevice(objpath) for objpath in result]
return devices
@GObject.Property
def themes(self):
"""A list of theme names. The theme 'default' is guaranteed to be
available."""
return self._get_dbus_property("Themes")
class RatbagdDevice(_RatbagdDBus):
"""Represents a ratbagd device."""
CAP_NONE = 0
CAP_QUERY_CONFIGURATION = 1
CAP_RESOLUTION = 100
CAP_SWITCHABLE_RESOLUTION = 101
CAP_PROFILE = 200
CAP_SWITCHABLE_PROFILE = 201
CAP_DISABLE_PROFILE = 202
CAP_DEFAULT_PROFILE = 203
CAP_BUTTON = 300
CAP_BUTTON_KEY = 301
CAP_BUTTON_MACROS = 302
CAP_LED = 400
def __init__(self, object_path):
_RatbagdDBus.__init__(self, "Device", object_path)
@GObject.Property
def id(self):
"""The unique identifier of this device."""
return self._get_dbus_property("Id")
@GObject.Property
def capabilities(self):
"""The capabilities of this device as an array. Capabilities not
present on the device are not in the list. Thus use e.g.
if RatbagdDevice.CAP_SWITCHABLE_RESOLUTION is in device.capabilities:
do something
"""
return self._get_dbus_property("Capabilities")
@GObject.Property
def name(self):
"""The device name, usually provided by the kernel."""
return self._get_dbus_property("Name")
@GObject.Property
def profiles(self):
"""A list of RatbagdProfile objects provided by this device."""
profiles = []
result = self._get_dbus_property("Profiles")
if result is not None:
profiles = [RatbagdProfile(objpath) for objpath in result]
return profiles
def get_svg(self, theme):
"""Gets the full path to the SVG for the given theme, or the empty
string if none is available.
The theme must be one of org.freedesktop.ratbag1.Manager.Themes. The
theme 'default' is guaranteed to be available.
@param theme The theme from which to retrieve the SVG, as str
"""
return self._dbus_call("GetSvg", "s", theme)
def commit(self):
"""Commits all changes made to the device."""
return self._dbus_call("Commit", "")
class RatbagdProfile(_RatbagdDBus):
"""Represents a ratbagd profile."""
def __init__(self, object_path):
_RatbagdDBus.__init__(self, "Profile", object_path)
@GObject.Property
def index(self):
"""The index of this profile."""
return self._get_dbus_property("Index")
@GObject.Property
def enabled(self):
"""tells if the profile is enabled."""
return self._get_dbus_property("Enabled")
@enabled.setter
def enabled(self, enabled):
"""Enable/Disable this profile.
@param enabled The new state, as boolean"""
return self._set_dbus_property("Enabled", "b", enabled)
@GObject.Property
def resolutions(self):
"""A list of RatbagdResolution objects with this profile's resolutions.
"""
resolutions = []
result = self._get_dbus_property("Resolutions")
if result is not None:
resolutions = [RatbagdResolution(objpath) for objpath in result]
return resolutions
@GObject.Property
def buttons(self):
"""A list of RatbagdButton objects with this profile's button mappings.
Note that the list of buttons differs between profiles but the number
of buttons is identical across profiles."""
buttons = []
result = self._get_dbus_property("Buttons")
if result is not None:
buttons = [RatbagdButton(objpath) for objpath in result]
return buttons
@GObject.Property
def leds(self):
"""A list of RatbagdLed objects with this profile's leds."""
leds = []
result = self._get_dbus_property("Leds")
if result is not None:
leds = [RatbagdLed(objpath) for objpath in result]
return leds
@GObject.Property
def is_active(self):
"""Returns True if the profile is currenly active, false otherwise."""
return self._get_dbus_property("IsActive")
def set_active(self):
"""Set this profile to be the active profile."""
return self._dbus_call("SetActive", "")
class RatbagdResolution(_RatbagdDBus):
"""Represents a ratbagd resolution."""
CAP_INDIVIDUAL_REPORT_RATE = 1
CAP_SEPARATE_XY_RESOLUTION = 2
def __init__(self, object_path):
_RatbagdDBus.__init__(self, "Resolution", object_path)
@GObject.Property
def index(self):
"""The index of this resolution."""
return self._get_dbus_property("Index")
@GObject.Property
def capabilities(self):
"""The capabilities of this resolution as a list. Capabilities not
present on the resolution are not in the list. Thus use e.g.
if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION is in resolution.capabilities:
do something
"""
return self._get_dbus_property("Capabilities")
@GObject.Property
def resolution(self):
"""The tuple (xres, yres) with each resolution in DPI."""
return self._get_dbus_property("Resolution")
@resolution.setter
def resolution(self, res):
"""Set the x- and y-resolution using the given (xres, yres) tuple.
@param res The new resolution, as (int, int)
"""
ret = self._set_dbus_property("Resolution", "(uu)", res)
return ret
@GObject.Property
def report_rate(self):
"""The report rate in Hz."""
return self._get_dbus_property("ReportRate")
@GObject.Property
def maximum(self):
"""The maximum possible resolution."""
return self._get_dbus_property("Maximum")
@GObject.Property
def minimum(self):
"""The minimum possible resolution."""
return self._get_dbus_property("Minimum")
@report_rate.setter
def report_rate(self, rate):
"""Set the report rate in Hz.
@param rate The new report rate, as int
"""
return self._set_dbus_property("ReportRate", "u", rate)
@GObject.Property
def is_active(self):
"""True if this is the currently active resolution, False
otherwise"""
return self._get_dbus_property("IsActive")
@GObject.Property
def is_default(self):
"""True if this is the currently default resolution, False
otherwise"""
return self._get_dbus_property("IsDefault")
def set_default(self):
"""Set this resolution to be the default."""
return self._dbus_call("SetDefault", "")
def set_active(self):
"""Set this resolution to be the active one."""
return self._dbus_call("SetActive", "")
class RatbagdButton(_RatbagdDBus):
"""Represents a ratbagd button."""
ACTION_TYPE_NONE = 0
ACTION_TYPE_BUTTON = 1
ACTION_TYPE_SPECIAL = 2
ACTION_TYPE_KEY = 3
ACTION_TYPE_MACRO = 4
ACTION_SPECIAL_UNKNOWN = (1 << 30)
ACTION_SPECIAL_DOUBLECLICK = (1 << 30) + 1
ACTION_SPECIAL_WHEEL_LEFT = (1 << 30) + 2
ACTION_SPECIAL_WHEEL_RIGHT = (1 << 30) + 3
ACTION_SPECIAL_WHEEL_UP = (1 << 30) + 4
ACTION_SPECIAL_WHEEL_DOWN = (1 << 30) + 5
ACTION_SPECIAL_RATCHET_MODE_SWITCH = (1 << 30) + 6
ACTION_SPECIAL_RESOLUTION_CYCLE_UP = (1 << 30) + 7
ACTION_SPECIAL_RESOLUTION_CYCLE_DOWN = (1 << 30) + 8
ACTION_SPECIAL_RESOLUTION_UP = (1 << 30) + 9
ACTION_SPECIAL_RESOLUTION_DOWN = (1 << 30) + 10
ACTION_SPECIAL_RESOLUTION_ALTERNATE = (1 << 30) + 11
ACTION_SPECIAL_RESOLUTION_DEFAULT = (1 << 30) + 12
ACTION_SPECIAL_PROFILE_CYCLE_UP = (1 << 30) + 13
ACTION_SPECIAL_PROFILE_CYCLE_DOWN = (1 << 30) + 14
ACTION_SPECIAL_PROFILE_UP = (1 << 30) + 15
ACTION_SPECIAL_PROFILE_DOWN = (1 << 30) + 16
ACTION_SPECIAL_SECOND_MODE = (1 << 30) + 17
ACTION_SPECIAL_BATTERY_LEVEL = (1 << 30) + 18
MACRO_KEY_PRESS = 1
MACRO_KEY_RELEASE = 2
MACRO_WAIT = 3
TYPE_UNKNOWN = 0
TYPE_LEFT = 1
TYPE_MIDDLE = 2
TYPE_RIGHT = 3
TYPE_THUMB = 4
TYPE_THUMB2 = 5
TYPE_THUMB3 = 6
TYPE_THUMB4 = 7
TYPE_WHEEL_LEFT = 8
TYPE_WHEEL_RIGHT = 9
TYPE_WHEEL_CLICK = 10
TYPE_WHEEL_UP = 11
TYPE_WHEEL_DOWN = 12
TYPE_WHEEL_RATCHET_MODE_SHIFT = 13
TYPE_EXTRA = 14
TYPE_SIDE = 15
TYPE_PINKIE = 16
TYPE_PINKIE2 = 17
TYPE_RESOLUTION_CYCLE_UP = 18
TYPE_RESOLUTION_UP = 19
TYPE_RESOLUTION_DOWN = 20
TYPE_PROFILE_CYCLE_UP = 21
TYPE_PROFILE_UP = 22
TYPE_PROFILE_DOWN = 23
def __init__(self, object_path):
_RatbagdDBus.__init__(self, "Button", object_path)
@GObject.Property
def index(self):
"""The index of this button."""
return self._get_dbus_property("Index")
@GObject.Property
def type(self):
"""An enum describing this button's type."""
return self._get_dbus_property("Type")
@GObject.Property
def mapping(self):
"""An integer of the current button mapping, if mapping to a button."""
return self._get_dbus_property("ButtonMapping")
@mapping.setter
def mapping(self, button):
"""Set the button mapping to the given button.
@param button The button to map to, as int
"""
ret = self._set_dbus_property("ButtonMapping", "u", button)
self.notify("action-type")
return ret
@GObject.Property
def macro(self):
"""A list of (type, value) tuples that form the currently set macro,
where type is either RatbagdButton.KEY_PRESS, RatbagdButton.KEY_RELEASE
or RatbagdButton.MACRO_WAIT and the value is the keycode as specified
in linux/input.h for key related types, or the timeout in milliseconds."""
return self._get_dbus_property("Macro")
@macro.setter
def macro(self, macro):
"""Set the macro to the given macro. Note that the type must be one of
RatbagdButton.KEY_PRESS, RatbagdButton.KEY_RELEASE or
RatbagdButton.MACRO_WAIT and the keycodes must be as specified in
linux/input.h, and the timeout must be in milliseconds.
@param macro A list of (type, value) tuples to form the new macro.
"""
ret = self._set_dbus_property("Macro", "a(uu)", macro)
self.notify("action-type")
return ret
@GObject.Property
def special(self):
"""An enum describing the current special mapping, if mapped to special."""
return self._get_dbus_property("SpecialMapping")
@special.setter
def special(self, special):
"""Set the button mapping to the given special entry.
@param special The special entry, as one of RatbagdButton.ACTION_SPECIAL_*
"""
ret = self._set_dbus_property("SpecialMapping", "u", special)
self.notify("action-type")
return ret
@GObject.Property
def key(self):
"""A list of integers, the first being the keycode and the other
entries, if any, are modifiers (if mapped to key)."""
return self._get_dbus_property("KeyMapping")
@key.setter
def key(self, keys):
"""Set the key mapping.
@param keys A list of integers, the first being the keycode and the rest
modifiers.
"""
ret = self._set_dbus_property("KeyMapping", "au", keys)
self.notify("action-type")
return ret
@GObject.Property
def action_type(self):
"""An enum describing the action type of the button. One of
ACTION_TYPE_NONE, ACTION_TYPE_BUTTON, ACTION_TYPE_SPECIAL,
ACTION_TYPE_KEY, ACTION_TYPE_MACRO. This decides which
*Mapping property has a value.
"""
return self._get_dbus_property("ActionType")
@GObject.Property
def action_types(self):
"""An array of possible values for ActionType."""
return self._get_dbus_property("ActionTypes")
def disable(self):
"""Disables this button."""
return self._dbus_call("Disable", "")
class RatbagdLed(_RatbagdDBus):
"""Represents a ratbagd led."""
TYPE_UNKNOWN = -1
TYPE_LOGO = 0
TYPE_SIDE = 1
MODE_OFF = 0
MODE_ON = 1
MODE_CYCLE = 2
MODE_BREATHING = 3
def __init__(self, object_path):
_RatbagdDBus.__init__(self, "Led", object_path)
@GObject.Property
def index(self):
"""The index of this led."""
return self._get_dbus_property("Index")
@GObject.Property
def mode(self):
"""This led's mode, one of MODE_OFF, MODE_ON, MODE_CYCLE and
MODE_BREATHING."""
return self._get_dbus_property("Mode")
@mode.setter
def mode(self, mode):
"""Set the led's mode to the given mode.
@param mode The new mode, as one of MODE_OFF, MODE_ON, MODE_CYCLE and
MODE_BREATHING.
"""
return self._set_dbus_property("Mode", "u", mode)
@GObject.Property
def type(self):
"""An enum describing this led's type, one of RatbagdLed.TYPE_UNKNOWN,
RatbagdLed.TYPE_LOGO or RatbagdLed.TYPE_SIDE."""
return self._get_dbus_property("Type")
@GObject.Property
def color(self):
"""An integer triple of the current LED color."""
return self._get_dbus_property("Color")
@color.setter
def color(self, color):
"""Set the led color to the given color.
@param color An RGB color, as an integer triplet with values 0-255.
"""
return self._set_dbus_property("Color", "(uuu)", color)
@GObject.Property
def effect_rate(self):
"""The LED's effect rate in Hz, values range from 100 to 20000."""
return self._get_dbus_property("EffectRate")
@effect_rate.setter
def effect_rate(self, effect_rate):
"""Set the effect rate in Hz. Allowed values range from 100 to 20000.
@param effect_rate The new effect rate, as int
"""
return self._set_dbus_property("EffectRate", "u", effect_rate)
@GObject.Property
def brightness(self):
"""The LED's brightness, values range from 0 to 255."""
return self._get_dbus_property("Brightness")
@brightness.setter
def brightness(self, brightness):
"""Set the brightness. Allowed values range from 0 to 255.
@param brightness The new brightness, as int
"""
return self._set_dbus_property("Brightness", "u", brightness)

View File

@@ -283,8 +283,8 @@ struct ratbag_device *
ratbag_cmd_open_device(struct ratbag *ratbag, const char *path)
{
struct ratbag_device *device;
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
_cleanup_(udev_unrefp) struct udev *udev = NULL;
_cleanup_(udev_device_unrefp) struct udev_device *udev_device = NULL;
enum ratbag_error_code error;
udev = udev_new();

115
tools/toolbox.py Normal file
View File

@@ -0,0 +1,115 @@
# This file is part of libratbag.
#
# Copyright 2017 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import imp
import os
import shutil
import subprocess
import sys
# various constants
RATBAGCTL_NAME = 'ratbagctl'
RATBAGCTL_PATH = os.path.join('@MESON_BUILD_ROOT@', RATBAGCTL_NAME)
RATBAGCTL_DEVEL_NAME = 'ratbagctl.devel'
RATBAGCTL_DEVEL_PATH = os.path.join('@MESON_BUILD_ROOT@', RATBAGCTL_DEVEL_NAME)
DBUS_CONF_DIR = '/etc/dbus-1/system.d'
DBUS_CONF_NAME = 'org.freedesktop.ratbag_devel1.conf'
DBUS_CONF_PATH = os.path.join(DBUS_CONF_DIR, DBUS_CONF_NAME)
def import_non_standard_path(name, path):
# Fast path: see if the module has already been imported.
try:
return sys.modules[name]
except KeyError:
pass
# If any of the following calls raises an exception,
# there's a problem we can't handle -- let the caller handle it.
with open(path, 'rb') as fp:
module = imp.load_module(name, fp, os.path.basename(path), ('.py', 'rb', imp.PY_SOURCE))
return module
def start_ratbagd():
from gi.repository import Gio
import time
# first copy the policy for the ratbagd daemon to be allowed to run
shutil.copy(os.path.join('@MESON_BUILD_ROOT@',
DBUS_CONF_NAME),
DBUS_CONF_DIR)
# FIXME: kill any running ratbagd.devel
ratbagd_process = subprocess.Popen([os.path.join('@MESON_BUILD_ROOT@', "ratbagd.devel")], shell=False)
dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
name_owner = None
start_time = time.clock()
while name_owner is None and time.clock() - start_time < 30:
proxy = Gio.DBusProxy.new_sync(dbus,
Gio.DBusProxyFlags.NONE,
None,
"org.freedesktop.ratbag_devel1_@ratbagd_sha@",
"/org/freedesktop/ratbag_devel1_@ratbagd_sha@",
"org.freedesktop.ratbag_devel1_@ratbagd_sha@.Manager",
None)
name_owner = proxy.get_name_owner()
if name_owner is None:
time.sleep(0.2)
os.environ['RATBAGCTL_DEVEL'] = "org.freedesktop.ratbag_devel1_@ratbagd_sha@"
if name_owner is None or ratbagd_process.poll() is not None:
return None
return ratbagd_process
def terminate_ratbagd(ratbagd):
try:
ratbagd.terminate()
ratbagd.wait(5)
except subprocess.TimeoutExpired:
ratbagd.kill()
os.unlink(DBUS_CONF_PATH)
ratbagctl = import_non_standard_path(RATBAGCTL_NAME, RATBAGCTL_PATH)
from ratbagctl import open_ratbagd, get_parser
__all__ = [
RATBAGCTL_NAME,
RATBAGCTL_PATH,
DBUS_CONF_DIR,
DBUS_CONF_NAME,
DBUS_CONF_PATH,
start_ratbagd,
terminate_ratbagd,
open_ratbagd,
get_parser,
]