56 Commits

Author SHA1 Message Date
Peter Hutterer
3d345570eb meson.build: libratbag 0.9.903
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-09-05 08:41:26 +10:00
Peter Hutterer
6000688c30 ratbagd: add GetSvgFd() to return an fd to the SVG
If we're sandboxing the client we don't have access to the SVG files directly.
So pass a read-only file descriptor to the client over DBus and let them deal
with the SVG that way.

In ratbagd.py we pull the fd off but we convert the quirky dbus error into a
normal FileNotFoundError(), much easier to catch in the caller.

On the ratbagctl side we now have to search the SVG for it's name - stored in
the 'sodipodi:docname' attribute by Inkspace. This isn't guaranteed to exist
or be always correct, but meh, it's close enough. We could continue to use the
GetSvg() call here but I want to deprecate that and remove it in the near
future.

Fixes #521

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-09-05 08:31:35 +10:00
Rasmus Thomsen
9b409822c3 build: support building with elogind 2018-09-04 13:51:01 +10:00
FFY00
363eab80f0 steelseries: implement cycle struct 2018-09-01 22:49:32 +02:00
Peter Hutterer
66fc7b545e meson_options: fix indentation 2018-08-31 09:06:05 +10:00
Peter Hutterer
bb4b673df8 Drop the unused libratbag-version.h
Unused since 558f59b52c

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-30 08:20:23 +02:00
Peter Hutterer
e104eca02c ratbagd: add a --version commandline argument
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-30 08:20:23 +02:00
Peter Hutterer
01c362eadc ratbagd: log the device list by default
Without --verbose ratbagd just starts up with no message whatsoever. It's hard
to tell if any devices are supported or if the server just hangs. Let's log
the devices detected by default, at least that way we get some feedback.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-30 08:20:23 +02:00
Thomas Hindoe Paaboel Andersen
fff3589a20 steelseries: read settings from device
Open an extra hidraw to read current onboard settings.

Initially DPI and static LED color can be read from the rival
310. Other data/devices can be added as the protocol is better
understood.

The protocol used to extract the data seems to be both device
and firmware version specific. To be able to switch on both
cases we now store the firmware information in the drv_data.

Signed-off-by: Thomas Hindoe Paaboel Andersen <phomes@gmail.com>
2018-08-30 15:49:48 +10:00
Thomas Hindoe Paaboel Andersen
a4e1e1690d hidraw: allow opening multiple hidraw
For some devices we have to send reports on one endpoint
but read the reply on another. This commit allows us to
open and store multiple hidraws and adds API to specify
which hidraw to use for open, close, and read input report.

Signed-off-by: Thomas Hindoe Paaboel Andersen <phomes@gmail.com>
2018-08-30 15:49:48 +10:00
Peter Hutterer
38dce69838 ratbagd: remove some unused variables
Warnings introduced in 23ff4e753d

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-30 11:03:09 +10:00
Peter Hutterer
23ff4e753d ratbagd: wrap the various sd_bus functions into a macro
Make sure we log an error if any of these fail, because most really never
should, they're scaffolding we rely on to send the data. Some of these calls
(the *_read() ones) could fail if a client sends wrong data, but we might as
well log that.

This patch only wraps calls that reply on the bus, normal sd_bus_* calls that
we catch the error ourselves are handled as before.

Likewise, any errors from libratbag are left as-is. We somewhat rely on
libratbag to log something and such errors are not a failure of the actual
scaffolding.

This should make errors like https://github.com/libratbag/piper/issues/237
easier to debug.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-24 10:01:56 +02:00
Peter Hutterer
f24cb6dc66 ratbagd: always return an empty list for array-like properties []
In some cases we get Piper trying to use None as a list, see
https://github.com/libratbag/piper/issues/237

This can be reproduced by returning an error (e.g. -ENOMEM) from
ratbagd_get_devices(). That error isn't handled anywhere on the client side,
the effective result is that the property is None when calling
proxy.get_cached_property().

The error is visible on the bus:

method call time=1535084121.223284 sender=:1.1311 -> destination=:1.1310
  serial=7 path=/org/freedesktop/ratbag1;
  interface=org.freedesktop.DBus.Properties; member=GetAll
  string "org.freedesktop.ratbag1.Manager"
error time=1535084121.223433 sender=:1.1310 -> destination=:1.1311
  error_name=org.freedesktop.DBus.Error.NoMemory reply_serial=7
  string "Cannot allocate memory"

Make ratbagd.py more robust here and always return an empty list for those
properties where we expect an array. This papers over the real bug which is
that a) we need better logging in ratbagd on errors and b) something on the
other side needs to handle this error.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-24 10:01:56 +02:00
Thomas Hindoe Paaboel Andersen
b738136154 ratbagd: do not warn when converting invalid special action
Clients e.g. ratbagctl ask for all properties, so this getter gets
called often even if the button is not a special action.

We do not want to send the value for an invalid special action as
that is negative 1. Converting to unknown is good enough here so
let's just remove the error logging and convert in silence.
2018-08-23 08:04:57 +10:00
Peter Hutterer
447931d779 ratbagd: put in a check for invalid -1 sent down the wire
Before we send something as "u" down DBus, check that it's not -1, a commonly
used error code in libratbag. If so, return a dbus error instead and log where
this occured so we can fix it.

This should at least help spot these errors quickly while at the same time
hopefully not crashing piper anymore.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 20:21:55 +02:00
Peter Hutterer
920b71d94c ratbagd: if the action special type is invalid, change to unknown
This prevents us from sending -1 down the wire as unsigned int.

This may be the cause of https://github.com/libratbag/piper/issues/208

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 20:21:55 +02:00
Peter Hutterer
a786aaf390 libratbag: whitespace fixes
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 20:21:55 +02:00
Peter Hutterer
d395db1a11 libratbag: make the ratbag_*_has_* and _is_ functions return a bool
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 20:21:55 +02:00
Peter Hutterer
ad0b7e53d9 libratbag: use !! for the led modes
We don't want to leak the bitmask we use internally.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 20:21:55 +02:00
Peter Hutterer
0ed621db8f tools: make the dbus directory before trying to copy to it (#517)
Popped up in https://github.com/libratbag/libratbag/pull/515

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-22 04:08:10 +01:00
Peter Hutterer
5ae473dcd1 tools: make ratbagd a bit more robust regarding None object path lists
Not sure why this is happening exactly, but it's better to handle this case
without an immdiate exception.

Fixes https://github.com/libratbag/piper/issues/228

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-08-20 12:53:18 +10:00
maxice8
ac384137bd meson.build meson_options.txt: Add systemd switch (#510)
Allows systems that provide libelogind (which provides a portion of
libsystemd that libratbag uses) to also compile without having to patch
out the rest of the build to remove the full systemd dependency.

This commit:

- Adds a systemd swith on meson_options.txt, a boolean set to true as
default to keep expected behaivour
- Adds a check on meson.build for the systemd switch and adds
dep_systemd
- Guards sections meant to generate systemd service units under the
systemd switch
2018-08-16 23:33:42 +01:00
maxice8
e43cf7ab08 src/libratbag-data.c tools/lur-command.c: add missing limits.h includes (#507) 2018-08-16 12:46:36 +01:00
Thomas Hindoe Paaboel Andersen
acb65a1bc8 check-svg: only warn about non-consecutive buttons
Some devices like the logitech G9 have a button in its profile
data which is not a real physical button. This breaks the direct
mapping from button number to profile number.

This patch reduces this case from an error to a warning
2018-08-13 15:50:24 +10:00
Thomas Hindoe Paaboel Andersen
e5f4b49e36 update logitech G9 SVG
Adds wheel left/right clicks and adjusts button numberings

Button5 seems to be configurable in the profile, but no such button
exists on the mouse.
2018-08-13 15:50:24 +10:00
Thomas Hindoe Paaboel Andersen
31d0fa00d9 remove image layer in kinzu SVG 2018-07-30 09:43:47 +10:00
Thomas Hindoe Paaboel Andersen
d28f330d43 set profile dirty on name change 2018-07-30 09:42:25 +10:00
Thomas Hindoe Paaboel Andersen
a29adaf913 hidpp10: use profile name from device
Tested on G9
2018-07-30 09:42:25 +10:00
Thomas Hindoe Paaboel Andersen
ea3e68cf7d meson: bump min version to 0.40.0
Needed for build_by_default
2018-07-27 21:13:29 +10:00
gandalf3
158594ec20 Point buildsystem and piper at logitech-g900 svg 2018-07-27 10:19:09 +02:00
gandalf3
6e51849ae5 Add side view, space out leaders so Adwaita dropdowns don't overlap.
After some "user testing" (having a friend try it), I've put the side
view back in. This has the benefit of keeping all buttons visible
without overlap, which would be necessary for
https://github.com/libratbag/piper/issues/71.
2018-07-27 10:19:09 +02:00
gandalf3
29731aa578 Fix remaining missing leaders and add style properties 2018-07-27 10:19:09 +02:00
gandalf3
4d0ef4f2c1 Add buttons to device layer
Also set button ids for device layer button objects
2018-07-27 10:19:09 +02:00
gandalf3
e7d03448cc Add button ids to leader lines and add leader objects
Note: mouse up and mouse down ignored for now
2018-07-27 10:19:09 +02:00
gandalf3
2725a55770 Add LED and Button leads to logitech g600 svg 2018-07-27 10:19:09 +02:00
gandalf3
e5be1a70eb Add logitech G600 svg 2018-07-27 10:19:09 +02:00
Thomas Hindoe Paaboel Andersen
26493aceaf G600: fix setting resolution 2018-07-24 09:42:45 +02:00
Thomas Hindoe Paaboel Andersen
c4f5bd5218 Driver for logitech G600
A driver for the logitech G600. The behavior is similar to the
G300 but with enough differences that it seemed cleaner to implement
as a separate driver.
2018-07-24 09:42:45 +02:00
Thomas Hindoe Paaboel Andersen
7c65b0b4a9 increase max number of report rates to 8
This is needed for the logitech G600
2018-07-24 09:42:45 +02:00
Peter Hutterer
d81c68d94f meson: change to use "-Dtests=true" instead of "enable-tests"
This is more meson-like, the "enable-foo" is a autotools leftover.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-20 07:38:00 +02:00
Peter Hutterer
a5a2ea1a70 README: fix link to the DBus interface specification
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-18 14:59:03 +10:00
Peter Hutterer
507d10378a README: replace mesonconf with meson configure
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-18 08:12:18 +10:00
Gui Ambros
08f3f7daf2 Fix UTF-8 encoding on merge_ratbagd.py, per #493 2018-07-05 20:31:34 +02:00
Luke
9b848084fd data/gnome: added device entry for G203/G102, artwork needed (#490) 2018-07-05 03:01:35 +01:00
Peter Hutterer
e1ebf7ad1b Initialize a few _cleanup_ pointers to NULL
../src/liblur.c:46:3: warning: 'd' may be used uninitialized in this function [-Wmaybe-uninitialized]
   hidpp10_device_destroy(*hidpp10_device);
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/liblur.c:198:59: note: 'd' was declared here
   _cleanup_hidpp10_device_destroy_ struct hidpp10_device *d;

And similar messages

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2018-07-04 09:05:29 +02:00
Stephen Dawkins
38f46a9be8 updated sensei raw svg 2018-07-01 21:02:40 +02:00
Stephen Dawkins
d07b7582db removed sensei raw image from svg 2018-07-01 21:02:40 +02:00
Stephen Dawkins
af194a22f0 updated sensei raw image 2018-07-01 21:02:40 +02:00
Stephen Dawkins
d8c7050f6f disabled macros for steelseries if short_button is set 2018-07-01 21:02:40 +02:00
Stephen Dawkins
30e834b18b added svg for steelseries sensei raw 2018-07-01 21:02:40 +02:00
Stephen Dawkins
49770a22e7 added support for steelseries sensei raw 2018-07-01 21:02:40 +02:00
Thomas Hindoe Paaboel Andersen
de8cba13cf hidraw: use cleanup for udev enumerate 2018-06-29 11:25:03 +10:00
Benjamin Tissoires
1fab318dd3 hidpp20-drv: fix number of buttons for non-profiles mice
This was nasty. We correctly set the number of buttons but rely later
on the field set in drv_data.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-06-05 09:58:06 +10:00
Benjamin Tissoires
e2190964c2 hidpp20-drv: allow non configurable mice to work again
Given that there is a sanity check on the available resolution, we
need to provide default values. There might be a way to fetch the
actual values from the hardware but at least provide some sort of
default that re-enables the hardwares.

Fixes bacdab2596

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-06-05 09:58:06 +10:00
Benjamin Tissoires
8eddf99823 circle: allow to annotate clang static analyzer false positives
https://bugs.llvm.org/show_bug.cgi?id=3888

clang analyzer doesn't know how to handle __attribute__(cleanup()).

There are only 2 warnings raised because the analyzer only look at the
current compilation unit for checking the malloc call. So only those
2 are detected by clang and then marked as memory leak.

This also means our current continuous integration doesn't check for
memory leaks.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
2018-05-25 08:45:47 +02:00
p4block
9fede0e68d Add Logitech G302 2018-05-22 09:04:27 +02:00
44 changed files with 3507 additions and 476 deletions

View File

@@ -6,7 +6,7 @@ way to access the various features exposed by these mice and abstracts away
hardware-specific and kernel-specific quirks.
libratbag exports the devices over a DBus daemon called **ratbagd**, see the
[ratbagd DBus Interface description](DBusInterface.md).
[ratbagd DBus Interface description](https://libratbag.github.io/).
Compiling libratbag
-------------------
@@ -27,9 +27,9 @@ And to build or re-build after code-changes, run:
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
meson configure builddir -Denable-documentation=false
Run `mesonconf builddir` to list the options.
Run `meson configure builddir` to list the options.
Running ratbagd as DBus-activated systemd service
-------------------------------------------------

View File

@@ -124,13 +124,13 @@ scan_build_run: &scan_build_run
- *fedora_install
- run:
name: Install clang and find
command: dnf install -y clang-analyzer findutils
command: dnf install -y clang-analyzer findutils python3-beautifulsoup4
- 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)
command: python3 ~/libratbag/tools/check_scan_build.py ~/libratbag/build/meson-logs/scanbuild
doc_build: &doc_build
<<: *default_settings

View File

@@ -0,0 +1,7 @@
# G102 and G203 (USB)
[Device]
Name=Logitech Gaming Mouse G102/G103
DeviceMatch=usb:046d:c084
Svg=logitech-g102-g203.svg
Driver=hidpp20
LedTypes=logo;side;

View File

@@ -0,0 +1,7 @@
# G302 over USB
[Device]
Name=Logitech Gaming Mouse G302
DeviceMatch=usb:046d:c07f
Svg=logitech-g303.svg
Driver=hidpp20
LedTypes=logo;side;

View File

@@ -0,0 +1,6 @@
# WARNING: this file was automatically converted and has not yet been vetted
[Device]
Name=Logitech G600
DeviceMatch=usb:046d:c24a
Driver=logitech_g600
Svg=logitech-g600.svg

View File

@@ -0,0 +1,15 @@
[Device]
Name=SteelSeries Sensei Raw
DeviceMatch=usb:1038:1369
Driver=steelseries
Svg=steelseries-senseiraw.svg
LedTypes=logo;dpi
[Driver/steelseries]
DeviceVersion=1
Buttons=8
Leds=1
DpiRange=90:5670@90
MacroLength=1
MonoLed=1
ShortButton=1

View File

@@ -49,7 +49,7 @@ def check_layers(root):
def check_elements(root, prefix, required=0):
"""
Checks for elements of the form 'prefixN' in the root tag. Any elements
found must be consecutive or an error is printed, i.e. if there's a
found must be consecutive or an warning is printed, i.e. if there's a
'button8' there has to be a 'button7'.
If required is nonzero, an error is logged for any missing element with
@@ -70,7 +70,7 @@ def check_elements(root, prefix, required=0):
highest = idx
previous = '{}{}'.format(prefix, idx - 1)
if idx > 0 and previous not in element_ids:
logger.error("Non-consecutive {}: {}".format(prefix, e))
logger.warning("Non-consecutive {}: {}".format(prefix, e))
leader = '{}{}-leader'.format(prefix, idx)
if leader not in element_ids:

View File

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

1190
data/gnome/logitech-g600.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 95 KiB

View File

@@ -14,8 +14,8 @@
viewBox="0 0 129.64583 129.64583"
version="1.1"
id="svg8"
sodipodi:docname="G9.svg"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="logitech-g9.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
enable-background="new">
<defs
id="defs2">
@@ -38,16 +38,16 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="108.9024"
inkscape:cy="270.58583"
inkscape:zoom="8.0000004"
inkscape:cx="264.58829"
inkscape:cy="370.72481"
inkscape:document-units="px"
inkscape:current-layer="LEDs"
inkscape:current-layer="Device"
inkscape:document-rotation="0"
showgrid="false"
showguides="false"
showguides="true"
inkscape:window-width="1920"
inkscape:window-height="1136"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
@@ -55,8 +55,8 @@
inkscape:guide-bbox="true"
units="px"
inkscape:snap-global="false"
inkscape:measure-start="200.26,379.645"
inkscape:measure-end="199.294,334.274">
inkscape:measure-start="296.875,398.125"
inkscape:measure-end="288.375,379.75">
<inkscape:grid
type="xygrid"
id="grid78" />
@@ -71,12 +71,12 @@
id="guide81"
inkscape:locked="false" />
<sodipodi:guide
position="51.756014,88.614617"
position="-0.18708866,88.492936"
orientation="0,1"
id="guide83"
inkscape:locked="false" />
<sodipodi:guide
position="57.778386,76.729167"
position="13.758333,76.993746"
orientation="0,1"
id="guide85"
inkscape:locked="false" />
@@ -156,13 +156,13 @@
<path
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 34.611402,214.21326 -0.467722,5.00462 16.18317,-1.07576 0.04677,-4.77076 z"
id="button3"
id="button9"
inkscape:connector-curvature="0"
inkscape:label="#path896" />
<path
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 64.405272,212.43591 -14.066729,0.93544 0.02888,4.76741 13.98589,-0.84138 z"
id="button4"
id="button8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
inkscape:label="#path898" />
@@ -184,14 +184,14 @@
<path
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 24.274755,248.26339 c -0.124726,-9.60388 -0.342996,-10.78877 0.748354,-17.86696 0.576857,0.0935 1.153713,0.18709 1.73057,0.28063 -0.826308,5.86211 -1.652616,11.72422 -2.478924,17.58633 z"
id="button6"
id="button3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc"
inkscape:label="#path4606" />
<path
style="fill:#d9dad7;fill-opacity:1;stroke:#babdb6;stroke-width:0.61647916;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.104469,228.7594 c -0.561265,-0.0779 -1.122531,-0.15591 -1.683796,-0.23386 0.919852,-4.78635 2.120338,-8.77758 3.671614,-12.95589 -0.662606,4.39658 -1.325212,8.79317 -1.987818,13.18975 z"
id="button5"
id="button4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc"
inkscape:label="#path4608" />
@@ -207,6 +207,20 @@
id="button1"
inkscape:connector-curvature="0"
inkscape:label="#path4612" />
<path
transform="translate(0,164.70833)"
id="button6"
d="m 62.980849,30.452818 a 0.06589785,0.06589785 0 0 0 -0.046,0.02066 l -1.13998,1.23145 a 0.06589785,0.06589785 0 0 0 0.002,0.09147 l 1.13947,1.139465 a 0.06589785,0.06589785 0 0 0 0.10697,-0.07338 l -0.50385,-1.113628 0.50488,-1.205093 a 0.06589785,0.06589785 0 0 0 -0.0636,-0.09095 z"
style="display:inline;color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.25282338;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:connector-curvature="0"
inkscape:label="#path1016" />
<path
transform="translate(0,164.70833)"
id="button7"
d="m 75.28463,30.433444 a 0.06589785,0.06589785 0 0 1 0.046,0.02066 l 1.13998,1.23145 a 0.06589785,0.06589785 0 0 1 -0.002,0.09147 l -1.13947,1.139465 a 0.06589785,0.06589785 0 0 1 -0.10697,-0.07338 l 0.50385,-1.113628 -0.50488,-1.205093 a 0.06589785,0.06589785 0 0 1 0.0636,-0.09095 z"
style="display:inline;color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:0.25282338;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:connector-curvature="0"
inkscape:label="#path1016-3" />
</g>
<g
inkscape:groupmode="layer"
@@ -215,26 +229,26 @@
transform="translate(0,-2.6458338)"
style="display:inline">
<g
transform="matrix(0.26458333,0,0,0.26458333,40.502648,-13.272558)"
transform="matrix(0.26458333,0,0,0.26458333,40.502648,-1.1017221)"
style="display:inline"
id="button2-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 336.91912,170.14213 -225.57514,0.36405"
d="M 336.91912,169.83277 147.21994,169.67013 109.21898,124.50618"
id="path51"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
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="rect53"
width="6.999999"
height="6.999999"
x="107.41756"
y="166.91161" />
x="106.00334"
y="120.59612" />
<rect
y="169.75269"
x="336.91913"
y="169.31075"
x="336.56558"
height="1"
width="1"
id="button2-leader"
@@ -244,7 +258,7 @@
<g
transform="matrix(-0.26458333,0,0,-0.26458333,116.08398,94.455601)"
style="display:inline"
id="button3-path"
id="button9-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"
@@ -264,7 +278,7 @@
x="438.04599"
height="1"
width="1"
id="button3-leader"
id="button9-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
@@ -323,13 +337,13 @@
inkscape:label="#rect871" />
</g>
<g
transform="matrix(0.26458333,0,0,-0.26458333,13.573867,94.421678)"
transform="matrix(0.26458333,0,0,0.26458333,13.573867,4.9859563)"
style="display:inline"
id="button4-path"
id="button8-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 438.04598,191.7488 H 193.48839 l -29.95691,-26.43012"
d="m 438.04598,191.7488 -249.80759,-0.5 -23.58191,-19.43012"
id="path51-1-9-6-8-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
@@ -338,21 +352,21 @@
id="rect53-2-3-2-7-4"
width="6.999999"
height="6.999999"
x="160.13437"
y="161.68198" />
x="161.75937"
y="169.05698" />
<rect
y="191.3428"
x="438.04599"
height="1"
width="1"
id="button4-leader"
id="button8-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
transform="matrix(-0.26458333,0,0,-0.26458333,116.07548,106.30868)"
style="display:inline"
id="button5-path"
id="button4-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"
@@ -372,14 +386,14 @@
x="438.04599"
height="1"
width="1"
id="button5-leader"
id="button4-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
<g
transform="matrix(-0.26458333,0,0,-0.26458333,116.05287,118.29899)"
style="display:inline"
id="button6-path"
id="button3-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"
@@ -399,8 +413,62 @@
x="438.04599"
height="1"
width="1"
id="button3-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect871" />
</g>
<g
transform="matrix(-0.29294531,0,0,0.26458333,70.05035,-34.688457)"
style="display:inline"
id="button6-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 33.59277,251.21287 205.11339,-0.0974"
id="path966-9-6"
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-8-7"
width="6.999999"
height="6.999999"
x="29.446411"
y="247.53609" />
<rect
y="250.62447"
x="238.5843"
height="1"
width="1"
id="button6-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect875" />
</g>
<g
transform="matrix(0.26458333,0,0,0.26458333,40.372307,-13.288752)"
style="display:inline"
id="button7-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 336.91912,170.14213 -196.70014,0.23905"
id="path51-1-6"
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-0-7"
width="6.999999"
height="6.999999"
x="137.97041"
y="166.84467" />
<rect
y="169.75269"
x="336.91913"
height="1"
width="1"
id="button7-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>
@@ -411,13 +479,13 @@
transform="translate(0,-2.6458338)"
style="display:inline">
<g
transform="matrix(0.26458333,0,0,-0.26458333,13.686363,102.7808)"
transform="matrix(0.26458333,0,0,0.26458333,13.592814,20.269951)"
style="display:inline"
id="led0-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 438.04598,178.25732 H 151.75439 l -10.41041,-7.75114"
d="m 438.04598,178.25732 -267.54159,0.25 -31.41041,-32.75114"
id="path51-1-9-6-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
@@ -426,8 +494,8 @@
id="rect53-2-3-2-2"
width="6.999999"
height="6.999999"
x="137.02765"
y="165.93933" />
x="135.77765"
y="141.93933" />
<rect
y="177.79317"
x="438.04599"

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 739 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,497 @@
<?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="490"
height="490"
viewBox="0 0 129.64583 129.64583"
version="1.1"
id="svg8"
sodipodi:docname="steelseries-senseiraw.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4986862"
inkscape:cx="234.07051"
inkscape:cy="291.38143"
inkscape:document-units="px"
inkscape:current-layer="Device"
inkscape:document-rotation="0"
showgrid="false"
showguides="false"
inkscape:window-width="1920"
inkscape:window-height="1149"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
showborder="true"
inkscape:guide-bbox="true"
units="px"
inkscape:snap-global="false"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0">
<inkscape:grid
type="xygrid"
id="grid78" />
<sodipodi:guide
position="58.722772,112.40709"
orientation="0,1"
id="guide79"
inkscape:locked="false" />
<sodipodi:guide
position="39.611923,100.54373"
orientation="0,1"
id="guide81"
inkscape:locked="false" />
<sodipodi:guide
position="51.756014,88.614617"
orientation="0,1"
id="guide83"
inkscape:locked="false" />
<sodipodi:guide
position="57.778386,76.729167"
orientation="0,1"
id="guide85"
inkscape:locked="false" />
<sodipodi:guide
position="45.047078,64.795712"
orientation="0,1"
inkscape:locked="false"
id="guide87" />
<sodipodi:guide
position="57.646696,52.899321"
orientation="0,1"
id="guide89"
inkscape:locked="false" />
<sodipodi:guide
position="64.732676,142.09384"
orientation="1,0"
id="guide913"
inkscape:locked="false" />
<sodipodi:guide
position="-45.462545,31.805073"
orientation="0,1"
inkscape:locked="false"
id="guide944" />
</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="layer1"
inkscape:label="Image"
style="display:none"
sodipodi:insensitive="true" />
<g
inkscape:groupmode="layer"
id="Device"
inkscape:label="Device"
style="display:inline;opacity:1"
transform="translate(0,-167.35416)">
<path
style="display:inline;fill:#d3d3ce;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 61.118815,173.57187 c -6.81302,0.0662 -11.972394,1.52136 -16.073435,3.37344 -2.88728,1.31189 -4.888218,3.54982 -6.680729,5.62239 -2.215885,3.43407 -3.375386,5.63618 -3.970698,8.86355 -0.919394,7.49385 -0.194949,14.47321 -0.225672,22.62187 -0.0441,2.92144 0.321327,3.9908 0.09533,6.28385 -0.132292,4.05143 -0.413412,7.82174 -0.79375,11.90625 l -0.859895,11.9724 -1.190625,16.27187 c -0.0248,0.94258 -1e-6,1.65364 0.198437,2.57969 0.171855,0.8399 0.352238,1.03153 0.463021,1.52135 0.595312,2.4033 0.529166,3.99631 1.785937,7.2099 2.116666,4.23333 3.604948,6.84609 6.746875,10.71562 3.858506,4.06797 6.928936,5.67685 11.575518,7.34219 4.293136,1.39044 7.919768,1.65835 12.633854,1.78594 0,0 8.340581,-0.39932 12.633718,-1.78976 4.646582,-1.66534 7.717012,-3.27422 11.575518,-7.34219 3.141927,-3.86953 4.630209,-6.48229 6.746875,-10.71562 1.256771,-3.21359 1.190625,-4.8066 1.785937,-7.2099 0.110783,-0.48982 0.291166,-0.68145 0.463021,-1.52135 0.198438,-0.92605 0.223237,-1.63711 0.198437,-2.57969 l -1.190625,-16.27187 -0.717876,-8.98999 c -0.380338,-4.08451 -0.803477,-10.83723 -0.935769,-14.88866 -0.225999,-2.29305 -0.28663,-3.36241 -0.33073,-6.28385 -0.03072,-8.14866 0.835741,-15.12802 -0.08365,-22.62187 -0.595312,-3.22737 -1.470774,-5.42948 -3.686659,-8.86355 -1.792511,-2.07257 -3.793449,-4.3105 -6.680729,-5.62239 -4.101041,-1.85208 -9.260416,-3.30724 -16.073436,-3.37344 -3.028432,-0.0919 -5.294794,0.0499 -7.4082,0.004 z"
id="path926"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccc" />
<path
id="path5205"
style="display:inline;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
d="m 68.894015,173.48626 c 0.01741,1.97468 0.845255,8.1474 1.684943,11.60161 1.369264,5.63272 0.266853,23.47034 0.266853,23.47034 0,0 -2.042025,17.37272 -6.022897,17.27166 -3.980871,0.16348 -6.022896,-17.20924 -6.022896,-17.20924 0,0 -1.10241,-17.83762 0.266854,-23.47034 0.839687,-3.45421 1.667532,-9.62693 1.684942,-11.60161 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscccscc" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 64.695108,222.94948 c -0.606916,-0.009 -3.440676,-6.06643 -3.513997,-9.56014 -0.02982,-1.42071 0.176696,-1.66675 3.591511,-1.70532 3.503766,-0.0396 3.702586,0.22584 3.694867,1.62781 -0.01799,3.26716 -3.27008,9.64508 -3.772381,9.63765 z"
id="button7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss"
mask="none"
clip-path="none" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 95.121771,209.18914 c 0,0 -0.197205,17.71196 -1.241986,33.44373 -0.483924,7.28668 -1.491683,12.97597 -2.130552,18.3934 -0.45519,3.85988 0.58105,6.73694 2.373267,7.24471 1.728139,0.48961 3.747262,-3.87217 3.747262,-3.87217"
id="path4742"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssc" />
<path
sodipodi:nodetypes="csssc"
inkscape:connector-curvature="0"
id="path4744"
d="m 34.385075,208.66134 c 0,0 0.197205,17.71196 1.241986,33.44373 0.483924,7.28668 1.491683,12.97597 2.130552,18.3934 0.45519,3.85988 -0.58105,6.73694 -2.373267,7.24471 -1.728139,0.48961 -3.747262,-3.87217 -3.747262,-3.87217"
style="display:inline;opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 33.794256,226.79927 0.594666,-18.07871"
id="path58"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 35.720073,242.99898 c 0,0 -1.305894,-0.86732 -1.520495,-1.08633 -0.214601,-0.21901 -0.406023,-15.1316 -0.406023,-15.1316 l 1.116802,0.0102"
id="path56"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czcc" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 95.452345,226.07744 -0.362533,-16.8175"
id="path54"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 93.827188,242.82115 c 0,0 1.385456,-0.49501 1.574101,-0.65851 0.188645,-0.16351 0.05639,-16.17317 0.05639,-16.17317 l -0.703725,-0.17593"
id="path52"
inkscape:connector-curvature="0"
sodipodi:nodetypes="czcc" />
<path
sodipodi:type="arc"
style="display:inline;opacity:1;fill:none;fill-opacity:0.39215686;stroke:#babdb6;stroke-width:3.62082291;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="led0"
sodipodi:cx="64.822914"
sodipodi:cy="280.68228"
sodipodi:rx="6.5174346"
sodipodi:ry="6.5174413"
d="m 69.431436,276.07375 a 6.5174346,6.5174413 0 0 1 10e-7,9.21706 6.5174346,6.5174413 0 0 1 -9.217045,0 6.5174346,6.5174413 0 0 1 -10e-7,-9.21705"
sodipodi:start="5.4977871"
sodipodi:end="3.9269907"
sodipodi:open="true"
sodipodi:arc-type="arc"
inkscape:label="#led1" />
<path
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#babdb6;stroke-width:0.98636663;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 62.181167,187.21067 -0.0053,13.99772 c 0.798868,1.60491 0.79411,1.60258 2.56045,1.60804 1.9255,-0.003 1.931661,-0.005 2.733645,-1.59929 l -0.0049,-14.01641 c -0.79057,-1.56574 -0.793119,-1.57885 -2.72281,-1.60756 -1.766557,0.0242 -1.762015,0.025 -2.561099,1.6175 z"
id="button2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<rect
id="button0"
width="18.360525"
height="26.481527"
x="37.983463"
y="180.65782"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button0" />
<rect
id="button1"
width="19.0667"
height="26.834612"
x="72.056366"
y="179.95164"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button1" />
<rect
id="button4"
width="3.8839571"
height="16.242002"
x="32.334072"
y="209.96404"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button4" />
<rect
id="button3"
width="4.0605006"
height="15.006199"
x="32.334072"
y="227.2653"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button3" />
<rect
id="button5"
width="3.177783"
height="14.653111"
x="93.594673"
y="210.67021"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button5" />
<rect
id="button6"
width="3.3543267"
height="15.712373"
x="93.594673"
y="226.91222"
style="display:inline;fill:none;stroke-width:0.26458332"
inkscape:label="#button6" />
</g>
<g
inkscape:groupmode="layer"
id="Buttons"
inkscape:label="Buttons"
transform="translate(0,-2.6458338)"
style="display:inline">
<g
transform="matrix(-0.29294531,0,0,0.26458333,70.223399,-40.717196)"
style="display:inline"
id="button0-path"
inkscape:label="#button0-path">
<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 81.663449,250.50576 157.960771,0.0352"
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="79.083046"
y="247.00577" />
<rect
y="250.00575"
x="238.62422"
height="1"
width="1"
id="button0-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#button0-leader" />
</g>
<g
transform="matrix(0.26458333,0,0,0.26458333,40.529257,-19.549003)"
style="display:inline"
id="button1-path"
inkscape:label="#button1-path">
<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 336.91912,170.14213 -183.57514,0.36405"
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="149"
y="167" />
<rect
y="169.75269"
x="336.91913"
height="1"
width="1"
id="button1-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#button1-leader" />
</g>
<g
transform="matrix(-0.2847136,0,0,0.26458333,87.395313,-3.7692874)"
style="display:inline;opacity:1"
id="button2-path"
inkscape:label="#button2-path">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path964-6"
d="m 79.210952,122.6933 62.691188,68.76371 165.40155,1e-5"
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="#button2-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
id="button2-leader"
width="1"
height="1"
x="306.40533"
y="190.93378" />
<rect
y="117.94263"
x="76.303352"
height="6.999999"
width="6.999999"
id="rect974-5"
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
transform="matrix(0.26458333,0,0,0.26458333,13.523106,5.8698781)"
style="display:inline"
id="button7-path"
inkscape:label="#button7-path">
<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 438.5178,161.34199 H 204.22621 l -10.41041,7.75114"
id="path51-1-9-6-0"
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="rect53-2-3-2-2"
width="6.999999"
height="6.999999"
x="189"
y="167" />
<rect
y="160.86166"
x="437.87918"
height="1"
width="1"
id="button7-leader"
style="color:#000000;text-align:start;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#button7-leader" />
</g>
<g
inkscape:label="#button3-path"
id="button3-path"
style="display:inline"
transform="matrix(-0.29294531,0,0,0.26458333,58.364063,-10.132593)">
<path
inkscape:connector-curvature="0"
id="path64"
d="m 81.659897,250.49954 118.042313,0.0476"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1.00572562;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="247.00577"
x="79.083046"
height="6.999999"
width="6.999999"
id="rect66"
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="#button3-leader"
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="199.22597"
y="250.00575" />
</g>
<g
transform="matrix(-0.29294531,0,0,0.26458333,58.488898,4.7227855)"
style="display:inline"
id="button4-path"
inkscape:label="#button4-path">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1.00572562;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 81.659897,250.49954 118.042313,0.0476"
id="path72"
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="rect74"
width="6.999999"
height="6.999999"
x="79.083046"
y="247.00577" />
<rect
y="250.00575"
x="199.15065"
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"
inkscape:label="#button4-leader" />
</g>
<g
transform="matrix(0.29294531,0,0,0.26458333,71.117413,-9.779506)"
style="display:inline"
id="button5-path"
inkscape:label="#button5-path">
<path
sodipodi:nodetypes="cc"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1.00572562;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 81.659897,250.49954 118.042313,0.0476"
id="path80"
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="rect82"
width="6.999999"
height="6.999999"
x="79.083046"
y="247.00577" />
<rect
y="250.00575"
x="199.22597"
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="#button5-leader" />
</g>
<g
inkscape:label="#button6-path"
id="button6-path"
style="display:inline"
transform="matrix(0.29294531,0,0,0.26458333,70.992573,5.0758725)">
<path
inkscape:connector-curvature="0"
id="path88"
d="m 81.659897,250.49954 118.042313,0.0476"
style="color:#000000;overflow:visible;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1.00572562;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="247.00577"
x="79.083046"
height="6.999999"
width="6.999999"
id="rect90"
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="#button6-leader"
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="199.15065"
y="250.00575" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="LEDs"
inkscape:label="LEDs"
transform="translate(0,-2.6458338)"
style="display:inline">
<g
transform="matrix(-0.29294531,0,0,0.26458333,70.145744,50.590488)"
style="display:inline"
id="led0-path"
inkscape:label="#led0-path">
<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 19.28901,250.49471 219.01243,0.008"
id="path966-0-2"
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-2-1"
width="6.999999"
height="6.999999"
x="16.834169"
y="246.63705" />
<rect
y="249.97328"
x="237.7849"
height="1"
width="1"
id="led0-leader"
style="color:#000000;text-align:end;overflow:visible;vector-effect:none;fill:#888a85;fill-opacity:1;stroke:none;stroke-linecap:round"
inkscape:label="#rect875" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -129,6 +129,19 @@ org.freedesktop.ratbag1.Device
This is the case if the device has SVGs available but not
for the given theme.
.. js:function:: GetSvgFd(s) → (h)
:param s: the theme name
:returns: An open file descriptor to the SVG for the given theme
Returns an open file descriptor to the SVG for the given theme or an
errno on error. The theme must be one of :js:attr:`Themes`.
The theme **'default'** is guaranteed to be available.
ratbagd may return ENOENT if a file doesn't exist.
This is the case if the device has SVGs available but not
for the given theme.
.. js:function:: Resync()
:type: Signal

View File

@@ -1,8 +1,8 @@
project('libratbag', 'c', 'cpp',
version : '0.9.902',
version : '0.9.903',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.38.0')
meson_version : '>= 0.40.0')
libratbag_version = meson.project_version().split('.')
@@ -38,6 +38,7 @@ add_project_arguments(cppflags, language: 'cpp')
# is generated at the end of this file
config_h = configuration_data()
config_h.set('_GNU_SOURCE', '1')
config_h.set_quoted('RATBAG_VERSION', meson.project_version())
config_h.set_quoted('FALLBACK_SVG_NAME', 'fallback.svg')
libratbag_data_dir = join_paths(get_option('prefix'),
get_option('datadir'),
@@ -49,11 +50,20 @@ config_h.set_quoted('LIBRATBAG_DATA_DIR', libratbag_data_dir)
pkgconfig = import('pkgconfig')
dep_udev = dependency('libudev')
dep_libevdev = dependency('libevdev')
dep_libsystemd = dependency('libsystemd', version : '>=227')
dep_systemd = dependency('systemd')
dep_glib = dependency('glib-2.0')
dep_lm = cc.find_library('m')
if get_option('logind-provider') == 'elogind'
logind_dep = dependency('libelogind', version : '>=227')
else
logind_dep = dependency('libsystemd', version : '>=227')
endif
enable_systemd = get_option('systemd')
if enable_systemd
dep_systemd = dependency('systemd')
endif
#### libutil.a ####
src_libutil = [
'src/libratbag-util.c',
@@ -131,6 +141,7 @@ src_libratbag = [
'src/driver-hidpp20.c',
'src/driver-hidpp10.c',
'src/driver-logitech-g300.c',
'src/driver-logitech-g600.c',
'src/driver-roccat.c',
'src/driver-gskill.c',
'src/driver-steelseries.c',
@@ -155,15 +166,6 @@ deps_libratbag = [
dep_libhidpp,
]
libratbag_version_h_config = configuration_data()
libratbag_version_h_config.set_quoted('LIBRATBAG_VERSION', meson.project_version())
libratbag_version_h = configure_file(
output : 'libratbag-version.h',
configuration : libratbag_version_h_config,
install: false,
)
lib_libratbag = static_library('ratbag',
src_libratbag,
include_directories : include_directories('.'),
@@ -244,6 +246,7 @@ man_lur_command = configure_file (
data_files = files(
'data/devices/etekcity-scroll-alpha.device',
'data/devices/gskill-MX-780.device',
'data/devices/logitech-g102-g203.device',
'data/devices/logitech-g300.device',
'data/devices/logitech-g303.device',
'data/devices/logitech-g403.device',
@@ -253,6 +256,7 @@ data_files = files(
'data/devices/logitech-g502-Proteus-Spectrum-over-USB.device',
'data/devices/logitech-g5-2007.device',
'data/devices/logitech-g5.device',
'data/devices/logitech-g600.device',
'data/devices/logitech-g602.device',
'data/devices/logitech-g700.device',
'data/devices/logitech-g700s.device',
@@ -275,6 +279,7 @@ data_files = files(
'data/devices/steelseries-kinzu-v2.device',
'data/devices/steelseries-rival-310.device',
'data/devices/steelseries-sensei-310.device',
'data/devices/steelseries-sensei-raw.device',
)
install_data(data_files,
@@ -289,12 +294,14 @@ test('data-parse-test', data_parse_test,
gnome_svg_files = files(
'data/gnome/fallback.svg',
'data/gnome/logitech-g102-g203.svg',
'data/gnome/logitech-g300.svg',
'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-g600.svg',
'data/gnome/logitech-g700.svg',
'data/gnome/logitech-g703.svg',
'data/gnome/logitech-g9.svg',
@@ -303,6 +310,7 @@ gnome_svg_files = files(
'data/gnome/steelseries-kinzu-v2.svg',
'data/gnome/steelseries-rival310.svg',
'data/gnome/steelseries-sensei310.svg',
'data/gnome/steelseries-senseiraw.svg',
)
install_data(gnome_svg_files,
install_dir : join_paths(get_option('datadir'), 'libratbag', 'gnome'))
@@ -311,7 +319,7 @@ test_svg_files = find_program('data/gnome/check-svg.py')
test('check-svg', test_svg_files, args : gnome_svg_files)
#### tests ####
enable_tests = get_option('enable-tests')
enable_tests = get_option('tests')
if enable_tests
dep_check = dependency('check', version: '>= 0.9.10')
@@ -399,7 +407,7 @@ src_ratbagd = [
deps_ratbagd = [
dep_udev,
dep_libsystemd,
logind_dep,
dep_libratbag,
]
@@ -430,35 +438,39 @@ configure_file(input : 'dbus/org.freedesktop.ratbag_devel1.conf.in',
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>
if enable_systemd
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
See https://github.com/libratbag/libratbag/issues/188
'''.format(default_unitdir))
unitdir = default_unitdir
else
unitdir = intended_unitdir
endif
endif
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)
if enable_systemd
configure_file(input : 'ratbagd/ratbagd.service.in',
output : 'ratbagd.service',
configuration : config_bindir,
install_dir : unitdir)
endif
dbusdir = get_option('dbus-root-dir')
if dbusdir == ''

View File

@@ -1,9 +1,9 @@
option('udev-dir',
type: 'string',
value: '',
description: 'udev base directory [default=$prefix/lib/udev]')
type: 'string',
value: '',
description: 'udev base directory [default=$prefix/lib/udev]')
option('enable-tests',
option('tests',
type: 'boolean',
value: true,
description: 'Build the tests (default=yes)')
@@ -27,3 +27,16 @@ option('dbus-group',
type: 'string',
value : '',
description : 'The UNIX group that is granted access to the ratbagd D-Bus service. By default all users may access it.')
option('systemd',
type : 'boolean',
value : true,
description : 'Build systemd unit files'
)
option('logind-provider',
type : 'combo',
choices: [ 'elogind', 'systemd'],
value : 'systemd',
description : 'Which logind provider to use'
)

View File

@@ -58,6 +58,8 @@ static int ratbagd_button_get_type(sd_bus *bus,
t = ratbag_button_get_type(button->lib_button);
verify_unsigned_int(t);
return sd_bus_message_append(reply, "u", t);
}
@@ -74,6 +76,8 @@ static int ratbagd_button_get_button(sd_bus *bus,
b = ratbag_button_get_button(button->lib_button);
verify_unsigned_int(b);
return sd_bus_message_append(reply, "u", b);
}
@@ -128,8 +132,14 @@ static int ratbagd_button_get_special(sd_bus *bus,
enum ratbag_button_action_special special;
special = ratbag_button_get_special(button->lib_button);
if (special == RATBAG_BUTTON_ACTION_SPECIAL_INVALID)
special = RATBAG_BUTTON_ACTION_SPECIAL_UNKNOWN;
return sd_bus_message_append(reply, "u", special);
verify_unsigned_int(special);
CHECK_CALL(sd_bus_message_append(reply, "u", special));
return 0;
}
static int ratbagd_button_set_special(sd_bus *bus,
@@ -144,9 +154,7 @@ static int ratbagd_button_set_special(sd_bus *bus,
enum ratbag_button_action_special special;
int r;
r = sd_bus_message_read(m, "u", &special);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "u", &special));
r = ratbag_button_set_special(button->lib_button, special);
@@ -180,12 +188,9 @@ static int ratbagd_button_get_macro(sd_bus *bus,
{
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "(uu)"));
macro = ratbag_button_get_macro(button->lib_button);
if (!macro)
@@ -213,13 +218,16 @@ static int ratbagd_button_get_macro(sd_bus *bus,
abort();
}
r = sd_bus_message_append(reply, "(uu)", type, value);
if (r < 0)
return r;
verify_unsigned_int(type);
verify_unsigned_int(value);
CHECK_CALL(sd_bus_message_append(reply, "(uu)", type, value));
}
out:
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_button_set_macro(sd_bus *bus,
@@ -235,9 +243,7 @@ static int ratbagd_button_set_macro(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_enter_container(m, 'a', "(uu)"));
macro = ratbag_button_macro_new("macro");
while ((r = sd_bus_message_read(m, "(uu)", &type, &value)) > 0) {
@@ -251,9 +257,7 @@ static int ratbagd_button_set_macro(sd_bus *bus,
if (r < 0)
return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_exit_container(m));
r = ratbag_button_set_macro(button->lib_button, macro);
if (r < 0) {
@@ -295,7 +299,11 @@ static int ratbagd_button_get_action_type(sd_bus *bus,
if (type == RATBAG_BUTTON_ACTION_TYPE_KEY)
type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
return sd_bus_message_append(reply, "u", type);
verify_unsigned_int(type);
CHECK_CALL(sd_bus_message_append(reply, "u", type));
return 0;
}
static int ratbagd_button_get_action_types(sd_bus *bus,
@@ -307,7 +315,6 @@ static int ratbagd_button_get_action_types(sd_bus *bus,
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,
@@ -316,20 +323,19 @@ static int ratbagd_button_get_action_types(sd_bus *bus,
enum ratbag_button_action_type *t;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "u"));
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;
verify_unsigned_int(*t);
CHECK_CALL(sd_bus_message_append(reply, "u", *t));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_button_disable(sd_bus_message *m,
@@ -339,9 +345,7 @@ static int ratbagd_button_disable(sd_bus_message *m,
struct ratbagd_button *button = userdata;
int r;
r = sd_bus_message_read(m, "");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, ""));
r = ratbag_button_disable(button->lib_button);
if (r < 0) {
@@ -351,7 +355,9 @@ static int ratbagd_button_disable(sd_bus_message *m,
return r;
}
return sd_bus_reply_method_return(m, "u", 0);
CHECK_CALL(sd_bus_reply_method_return(m, "u", 0));
return 0;
}
const sd_bus_vtable ratbagd_button_vtable[] = {

View File

@@ -130,7 +130,9 @@ static int ratbagd_device_get_device_name(sd_bus *bus,
name = "";
}
return sd_bus_message_append(reply, "s", name);
CHECK_CALL(sd_bus_message_append(reply, "s", name));
return 0;
}
static int ratbagd_device_get_svg(sd_bus *bus,
@@ -151,7 +153,9 @@ static int ratbagd_device_get_svg(sd_bus *bus,
svg = "";
}
return sd_bus_message_append(reply, "s", svg);
CHECK_CALL(sd_bus_message_append(reply, "s", svg));
return 0;
}
static int ratbagd_device_get_theme_svg(sd_bus_message *m,
@@ -162,17 +166,13 @@ static int ratbagd_device_get_theme_svg(sd_bus_message *m,
char svg_path[PATH_MAX] = {0};
const char *theme;
const char *svg;
int r;
const char *datadir;
datadir = getenv("LIBRATBAG_DATA_DIR");
if (!datadir)
datadir = LIBRATBAG_DATA_DIR;
r = sd_bus_message_read(m, "s", &theme);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "s", &theme));
svg = ratbag_device_get_svg_name(device->lib_device);
if (!svg) {
@@ -183,7 +183,48 @@ static int ratbagd_device_get_theme_svg(sd_bus_message *m,
snprintf(svg_path, sizeof(svg_path), "%s/%s/%s", datadir, theme, svg);
return sd_bus_reply_method_return(m, "s", svg_path);
CHECK_CALL(sd_bus_reply_method_return(m, "s", svg_path));
return 0;
}
static int ratbagd_device_get_theme_svg_fd(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;
const char *datadir;
_cleanup_close_ int fd = -1;
datadir = getenv("LIBRATBAG_DATA_DIR");
if (!datadir)
datadir = LIBRATBAG_DATA_DIR;
CHECK_CALL(sd_bus_message_read(m, "s", &theme));
svg = ratbag_device_get_svg_name(device->lib_device);
if (!svg) {
log_error("%s: failed to fetch SVG, using fallback\n",
ratbagd_device_get_sysname(device));
svg = FALLBACK_SVG_NAME;
}
snprintf(svg_path, sizeof(svg_path), "%s/%s/%s", datadir, theme, svg);
fd = open(svg_path, O_RDONLY);
if (fd == -1) {
log_error("%s: failed to open SVG '%s' (%m)\n",
ratbagd_device_get_sysname(device),
svg_path);
return -ENOENT;
}
CHECK_CALL(sd_bus_reply_method_return(m, "h", fd));
return 0;
}
static int ratbagd_device_get_profiles(sd_bus *bus,
@@ -197,25 +238,22 @@ static int ratbagd_device_get_profiles(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "o"));
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;
CHECK_CALL(sd_bus_message_append(reply,
"o",
ratbagd_profile_get_path(profile)));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_device_commit(sd_bus_message *m,
@@ -233,7 +271,9 @@ static int ratbagd_device_commit(sd_bus_message *m,
return r;
}
return sd_bus_reply_method_return(m, "u", 0);
CHECK_CALL(sd_bus_reply_method_return(m, "u", 0));
return 0;
}
static int
@@ -261,23 +301,20 @@ ratbagd_device_get_capabilities(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "u"));
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;
CHECK_CALL(sd_bus_message_append(reply, "u", cap));
}
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
const sd_bus_vtable ratbagd_device_vtable[] = {
@@ -288,6 +325,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = {
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("GetSvgFd", "s", "h", ratbagd_device_get_theme_svg_fd, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Commit", "", "u", ratbagd_device_commit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("Resync", "", 0),
SD_BUS_VTABLE_END,
@@ -324,10 +362,10 @@ int ratbagd_device_new(struct ratbagd_device **out,
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",
sysname,
ratbag_device_get_name(lib_device),
device->n_profiles);
log_info("%s: \"%s\", %d profiles\n",
sysname,
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);

View File

@@ -50,20 +50,19 @@ static int ratbagd_led_get_modes(sd_bus *bus,
{
struct ratbagd_led *led = userdata;
enum ratbag_led_mode mode = 0;
int r;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "u"));
while (mode <= RATBAG_LED_BREATHING) {
if (ratbag_led_has_mode(led->lib_led, mode))
sd_bus_message_append(reply, "u", mode);
CHECK_CALL(sd_bus_message_append(reply, "u", mode));
mode++;
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_led_get_mode(sd_bus *bus,
@@ -78,7 +77,12 @@ static int ratbagd_led_get_mode(sd_bus *bus,
enum ratbag_led_mode mode;
mode = ratbag_led_get_mode(led->lib_led);
return sd_bus_message_append(reply, "u", mode);
verify_unsigned_int(mode);
CHECK_CALL(sd_bus_message_append(reply, "u", mode));
return 0;
}
static int ratbagd_led_set_mode(sd_bus *bus,
@@ -93,9 +97,7 @@ static int ratbagd_led_set_mode(sd_bus *bus,
enum ratbag_led_mode mode;
int r;
r = sd_bus_message_read(m, "u", &mode);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "u", &mode));
r = ratbag_led_set_mode(led->lib_led, mode);
@@ -124,7 +126,11 @@ static int ratbagd_led_get_type(sd_bus *bus,
type = ratbag_led_get_type(led->lib_led);
return sd_bus_message_append(reply, "u", type);
verify_unsigned_int(type);
CHECK_CALL(sd_bus_message_append(reply, "u", type));
return 0;
}
static int ratbagd_led_get_color(sd_bus *bus,
@@ -139,7 +145,9 @@ static int ratbagd_led_get_color(sd_bus *bus,
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);
CHECK_CALL(sd_bus_message_append(reply, "(uuu)", c.red, c.green, c.blue));
return 0;
}
static int ratbagd_led_set_color(sd_bus *bus,
@@ -154,9 +162,7 @@ static int ratbagd_led_set_color(sd_bus *bus,
struct ratbag_color c;
int r;
r = sd_bus_message_read(m, "(uuu)", &c.red, &c.green, &c.blue);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "(uuu)", &c.red, &c.green, &c.blue));
if (c.red > 255)
c.red = 255;
@@ -191,7 +197,12 @@ static int ratbagd_led_get_effect_duration(sd_bus *bus,
int rate;
rate = ratbag_led_get_effect_duration(led->lib_led);
return sd_bus_message_append(reply, "u", rate);
verify_unsigned_int(rate);
CHECK_CALL(sd_bus_message_append(reply, "u", rate));
return 0;
}
static int ratbagd_led_set_effect_duration(sd_bus *bus,
@@ -206,9 +217,7 @@ static int ratbagd_led_set_effect_duration(sd_bus *bus,
unsigned int rate;
int r;
r = sd_bus_message_read(m, "u", &rate);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "u", &rate));
if (rate > 10000)
rate = 10000;
@@ -239,7 +248,12 @@ static int ratbagd_led_get_brightness(sd_bus *bus,
unsigned int brightness;
brightness = ratbag_led_get_brightness(led->lib_led);
return sd_bus_message_append(reply, "u", brightness);
verify_unsigned_int(brightness);
CHECK_CALL(sd_bus_message_append(reply, "u", brightness));
return 0;
}
static int ratbagd_led_set_brightness(sd_bus *bus,
@@ -254,9 +268,7 @@ static int ratbagd_led_set_brightness(sd_bus *bus,
unsigned int brightness;
int r;
r = sd_bus_message_read(m, "u", &brightness);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "u", &brightness));
if (brightness > 255)
brightness = 255;

View File

@@ -102,25 +102,22 @@ static int ratbagd_profile_get_resolutions(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "o"));
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;
CHECK_CALL(sd_bus_message_append(reply,
"o",
ratbagd_resolution_get_path(resolution)));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_profile_get_buttons(sd_bus *bus,
@@ -134,25 +131,22 @@ static int ratbagd_profile_get_buttons(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "o"));
for (i = 0; i < profile->n_buttons; ++i) {
button = profile->buttons[i];
if (!button)
continue;
r = sd_bus_message_append(reply,
CHECK_CALL(sd_bus_message_append(reply,
"o",
ratbagd_button_get_path(button));
if (r < 0)
return r;
ratbagd_button_get_path(button)));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_profile_get_leds(sd_bus *bus,
@@ -166,25 +160,22 @@ static int ratbagd_profile_get_leds(sd_bus *bus,
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;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "o"));
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;
CHECK_CALL(sd_bus_message_append(reply,
"o",
ratbagd_led_get_path(led)));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_profile_is_active(sd_bus *bus,
@@ -198,9 +189,11 @@ static int ratbagd_profile_is_active(sd_bus *bus,
struct ratbagd_profile *profile = userdata;
int is_active;
is_active = !!ratbag_profile_is_active(profile->lib_profile);
is_active = ratbag_profile_is_active(profile->lib_profile);
return sd_bus_message_append(reply, "b", is_active);
CHECK_CALL(sd_bus_message_append(reply, "b", is_active));
return 0;
}
static int ratbagd_profile_find_button(sd_bus *bus,
@@ -286,9 +279,7 @@ static int ratbagd_profile_set_active(sd_bus_message *m,
struct ratbagd_profile *profile = userdata;
int r;
r = sd_bus_message_read(m, "");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, ""));
r = ratbag_profile_set_active(profile->lib_profile);
if (r < 0) {
@@ -302,7 +293,9 @@ static int ratbagd_profile_set_active(sd_bus_message *m,
profile->device,
ratbagd_profile_active_signal_cb);
return sd_bus_reply_method_return(m, "u", 0);
CHECK_CALL(sd_bus_reply_method_return(m, "u", 0));
return 0;
}
static int
@@ -318,9 +311,7 @@ ratbagd_profile_set_enabled(sd_bus *bus,
int enabled;
int r;
r = sd_bus_message_read(m, "b", &enabled);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "b", &enabled));
r = ratbag_profile_set_enabled(profile->lib_profile, enabled);
if (r == 0) {
@@ -347,7 +338,9 @@ ratbagd_profile_is_enabled(sd_bus *bus,
struct ratbagd_profile *profile = userdata;
int enabled = ratbag_profile_is_enabled(profile->lib_profile) != 0;
return sd_bus_message_append(reply, "b", enabled);
CHECK_CALL(sd_bus_message_append(reply, "b", enabled));
return 0;
}
static int
@@ -363,9 +356,7 @@ ratbagd_profile_set_name(sd_bus *bus,
char *name;
int r;
r = sd_bus_message_read(m, "s", &name);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_read(m, "s", &name));
r = ratbag_profile_set_name(profile->lib_profile, name);
@@ -392,7 +383,9 @@ ratbagd_profile_get_name(sd_bus *bus,
struct ratbagd_profile *profile = userdata;
const char *name = ratbag_profile_get_name(profile->lib_profile);
return sd_bus_message_append(reply, "s", name);
CHECK_CALL(sd_bus_message_append(reply, "s", name));
return 0;
}
static int
@@ -410,23 +403,20 @@ ratbagd_profile_get_capabilities(sd_bus *bus,
enum ratbag_profile_capability caps[] = {
RATBAG_PROFILE_CAP_WRITABLE_NAME,
};
int r;
size_t i;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "u"));
for (i = 0; i < ELEMENTSOF(caps); i++) {
cap = caps[i];
if (ratbag_profile_has_capability(lib_profile, cap)) {
r = sd_bus_message_append(reply, "u", cap);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_append(reply, "u", cap));
}
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
const sd_bus_vtable ratbagd_profile_vtable[] = {

View File

@@ -167,7 +167,7 @@ ratbagd_resolution_is_active(sd_bus *bus,
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int is_active;
is_active = !!ratbag_resolution_is_active(lib_resolution);
is_active = ratbag_resolution_is_active(lib_resolution);
return sd_bus_message_append(reply, "b", is_active);
}
@@ -185,7 +185,7 @@ ratbagd_resolution_is_default(sd_bus *bus,
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
int is_default;
is_default = !!ratbag_resolution_is_default(lib_resolution);
is_default = ratbag_resolution_is_default(lib_resolution);
return sd_bus_message_append(reply, "b", is_default);
}
@@ -214,6 +214,7 @@ ratbagd_resolution_get_resolutions(sd_bus *bus,
assert(ndpis <= ARRAY_LENGTH(dpis));
for (unsigned int i = 0; i < ndpis; i++) {
verify_unsigned_int(dpis[i]);
r = sd_bus_message_append(reply, "u", dpis[i]);
if (r < 0)
return r;
@@ -238,6 +239,9 @@ ratbagd_resolution_get_resolution(sd_bus *bus,
xres = ratbag_resolution_get_dpi_x(lib_resolution);
yres = ratbag_resolution_get_dpi_y(lib_resolution);
verify_unsigned_int(xres);
verify_unsigned_int(yres);
return sd_bus_message_append(reply, "(uu)", xres, yres);
}
@@ -293,6 +297,7 @@ ratbagd_resolution_get_report_rate(sd_bus *bus,
int rate;
rate = ratbag_resolution_get_report_rate(lib_resolution);
verify_unsigned_int(rate);
return sd_bus_message_append(reply, "u", rate);
}
@@ -307,7 +312,7 @@ ratbagd_resolution_get_report_rates(sd_bus *bus,
{
struct ratbagd_resolution *resolution = userdata;
struct ratbag_resolution *lib_resolution = resolution->lib_resolution;
unsigned int rates[5];
unsigned int rates[8];
unsigned int nrates = ARRAY_LENGTH(rates);
int r;
@@ -320,6 +325,7 @@ ratbagd_resolution_get_report_rates(sd_bus *bus,
assert(nrates <= ARRAY_LENGTH(rates));
for (unsigned int i = 0; i < nrates; i++) {
verify_unsigned_int(rates[i]);
r = sd_bus_message_append(reply, "u", rates[i]);
if (r < 0)
return r;

View File

@@ -42,8 +42,12 @@
#include "ratbagd-test.h"
static bool verbose = false;
static bool verbose_raw = false;
enum log_level {
LL_QUIET = 1,
LL_INFO,
LL_VERBOSE,
LL_RAW,
} log_level = LL_INFO;
static const char *SVG_THEMES[] = {
"default",
@@ -51,13 +55,23 @@ static const char *SVG_THEMES[] = {
NULL
};
void log_info(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (log_level >= LL_INFO)
vprintf(fmt, args);
va_end(args);
}
void log_verbose(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (verbose)
if (log_level >= LL_VERBOSE)
vprintf(fmt, args);
va_end(args);
}
@@ -142,21 +156,18 @@ static int ratbagd_get_devices(sd_bus *bus,
{
struct ratbagd *ctx = userdata;
struct ratbagd_device *device;
int r;
r = sd_bus_message_open_container(reply, 'a', "o");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "o"));
RATBAGD_DEVICE_FOREACH(device, ctx) {
r = sd_bus_message_append(reply,
"o",
ratbagd_device_get_path(device));
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_append(reply,
"o",
ratbagd_device_get_path(device)));
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static int ratbagd_get_themes(sd_bus *bus,
@@ -169,23 +180,18 @@ static int ratbagd_get_themes(sd_bus *bus,
{
struct ratbagd *ctx = userdata;
const char **theme;
int r;
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_open_container(reply, 'a', "s"));
theme = ctx->themes;
while(*theme) {
r = sd_bus_message_append(reply,
"s",
*theme);
if (r < 0)
return r;
CHECK_CALL(sd_bus_message_append(reply, "s", *theme));
theme++;
}
return sd_bus_message_close_container(reply);
CHECK_CALL(sd_bus_message_close_container(reply));
return 0;
}
static const sd_bus_vtable ratbagd_vtable[] = {
@@ -384,10 +390,10 @@ static int ratbagd_new(struct ratbagd **out)
if (!ctx->lib_ctx)
return -ENOMEM;
if (verbose_raw)
if (log_level >= LL_RAW)
ratbag_log_set_priority(ctx->lib_ctx,
RATBAG_LOG_PRIORITY_RAW);
else if (verbose)
else if (log_level >= LL_VERBOSE)
ratbag_log_set_priority(ctx->lib_ctx,
RATBAG_LOG_PRIORITY_DEBUG);
@@ -533,12 +539,17 @@ int main(int argc, char *argv[])
#endif
if (argc > 1) {
if (streq(argv[1], "--verbose=raw")) {
verbose_raw = true;
if (streq(argv[1], "--version")) {
printf("%s\n", RATBAG_VERSION);
return 0;
} else if (streq(argv[1], "--quiet")) {
log_level = LL_QUIET;
} else if (streq(argv[1], "--verbose=raw")) {
log_level = LL_RAW;
} else if (streq(argv[1], "--verbose")) {
verbose = true;
log_level = LL_VERBOSE;
} else {
fprintf(stderr, "Usage: %s [--verbose[=raw]]\n",
fprintf(stderr, "Usage: %s [--version | --quiet | --verbose[=raw]]\n",
program_invocation_short_name);
r = -EINVAL;
goto exit;

View File

@@ -54,9 +54,20 @@ struct ratbagd_resolution;
struct ratbagd_button;
struct ratbagd_led;
void log_info(const char *fmt, ...) _printf_(1, 2);
void log_verbose(const char *fmt, ...) _printf_(1, 2);
void log_error(const char *fmt, ...) _printf_(1, 2);
#define CHECK_CALL(_call) \
do { \
int _r = _call; \
if (_r < 0) { \
log_error("%s: '%s' failed with: %s\n", __func__, #_call, strerror(-_r)); \
return _r; \
} \
} while (0)
/*
* Profiles
*/
@@ -176,6 +187,19 @@ struct ratbagd_device *ratbagd_device_next(struct ratbagd_device *device);
(_device); \
_device = (_safe), \
_safe = (_safe) ? ratbagd_device_next(_safe) : NULL)
/* Verify that _val is not -1. This traps DBus API errors where we end up
* sending a valid-looking index across and then fail on the other side.
*
* do {} while(0) so we can terminate with a ; without the compiler
* complaining about an empty statement;
* */
#define verify_unsigned_int(_val) \
do { if ((int)_val == -1) { \
log_error("%s:%d - %s: expected unsigned int, got -1\n", __FILE__, __LINE__, __func__); \
return -EINVAL; \
} } while(0)
/*
* Context
*/

View File

@@ -987,7 +987,7 @@ gskill_read_resolutions(struct ratbag_profile *profile,
hz = GSKILL_MAX_POLLING_RATE / (report->polling_rate + 1);
for (i = 0; i < report->dpi_num; i++) {
_cleanup_resolution_ struct ratbag_resolution *resolution;
_cleanup_resolution_ struct ratbag_resolution *resolution = NULL;
unsigned int rates[] = { 500, 1000 }; /* let's assume that is true */
dpi_x = report->dpi_levels[i].x * GSKILL_DPI_UNIT;
@@ -1108,7 +1108,7 @@ gskill_update_resolutions(struct ratbag_profile *profile)
* lost on exit
*/
for (i = 0; i < GSKILL_NUM_DPI; i++) {
_cleanup_resolution_ struct ratbag_resolution *res;
_cleanup_resolution_ struct ratbag_resolution *res = NULL;
struct gskill_raw_dpi_level *level =
&report->dpi_levels[report->dpi_num];

View File

@@ -407,8 +407,14 @@ hidpp10drv_read_profile(struct ratbag_profile *profile)
if (rc)
return;
ratbag_profile_set_cap(profile, RATBAG_PROFILE_CAP_WRITABLE_NAME);
profile->is_enabled = p.enabled;
if (profile->name)
free(profile->name);
profile->name = strdup_safe((char*)p.name);
rc = hidpp10_get_current_profile(hidpp10, &idx);
if (rc == 0 && (unsigned int)idx == profile->index)
profile->is_active = true;
@@ -543,6 +549,7 @@ hidpp10drv_commit(struct ratbag_device *device)
return rc;
p.enabled = profile->is_enabled;
strncpy_safe((char*)p.name, profile->name, 24);
ratbag_profile_for_each_resolution(profile, resolution) {
p.dpi_modes[resolution->index].xres = resolution->dpi_x;
@@ -605,7 +612,7 @@ hidpp10drv_probe(struct ratbag_device *device)
goto err;
drv_data = zalloc(sizeof(*drv_data));
hidpp_device_init(&base, device->hidraw.fd);
hidpp_device_init(&base, device->hidraw[0].fd);
hidpp_device_set_log_handler(&base, hidpp10_log, HIDPP_LOG_PRIORITY_RAW, device);
typestr = ratbag_device_data_hidpp10_get_profile_type(device->data);

View File

@@ -716,6 +716,9 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
struct ratbag_device *device = profile->device;
struct ratbag *ratbag = device->ratbag;
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
struct ratbag_resolution *res;
unsigned int default_dpi = 1000;
unsigned int default_rate = 500;
int rc;
if (drv_data->capabilities & HIDPP_CAP_RESOLUTION_2200) {
@@ -734,8 +737,6 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
}
if (drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201) {
struct ratbag_resolution *res;
rc = hidpp20drv_read_resolution_dpi_2201(device);
if (rc < 0)
return rc;
@@ -756,13 +757,12 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
* they are from different sensors */
res->is_active = true;
}
return 0;
} else {
ratbag_profile_for_each_resolution(profile, res)
ratbag_resolution_set_dpi_list(res, &default_dpi, 1);
}
if (drv_data->capabilities & HIDPP_CAP_ADJUSTIBLE_REPORT_RATE_8060) {
struct ratbag_resolution *res;
rc = hidpp20drv_read_report_rate_8060(device);
if (rc < 0)
return rc;
@@ -771,6 +771,9 @@ hidpp20drv_read_resolution_dpi(struct ratbag_profile *profile)
ratbag_resolution_set_report_rate_list(res,
drv_data->report_rates,
drv_data->num_report_rates);
} else {
ratbag_profile_for_each_resolution(profile, res)
ratbag_resolution_set_report_rate_list(res, &default_rate, 1);
}
return 0;
@@ -1049,7 +1052,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
/* we read the profile once to get the correct number of
* supported buttons. */
if (!hidpp20drv_read_special_key_mouse(device))
device->num_buttons = drv_data->num_controls;
drv_data->num_buttons = drv_data->num_controls;
break;
}
case HIDPP_PAGE_BATTERY_LEVEL_STATUS: {
@@ -1074,7 +1077,7 @@ hidpp20drv_init_feature(struct ratbag_device *device, uint16_t feature)
/* we read the profile once to get the correct number of
* supported buttons. */
if (!hidpp20drv_read_kbd_reprogrammable_key(device))
device->num_buttons = drv_data->num_controls;
drv_data->num_buttons = drv_data->num_controls;
break;
}
case HIDPP_PAGE_ADJUSTABLE_REPORT_RATE: {
@@ -1163,8 +1166,6 @@ hidpp20drv_commit(struct ratbag_device *device)
if (!profile->dirty)
continue;
drv_data->profiles->profiles[profile->index].enabled = profile->is_enabled;
ratbag_profile_for_each_resolution(profile, resolution) {
if (resolution->is_active)
dpi_index = resolution->index;
@@ -1197,6 +1198,9 @@ hidpp20drv_commit(struct ratbag_device *device)
}
if (drv_data->capabilities & HIDPP_CAP_ONBOARD_PROFILES_8100) {
list_for_each(profile, &device->profiles, link)
drv_data->profiles->profiles[profile->index].enabled = profile->is_enabled;
rc = hidpp20_onboard_profiles_commit(drv_data->dev,
drv_data->profiles);
if (rc)
@@ -1306,7 +1310,7 @@ hidpp20drv_probe(struct ratbag_device *device)
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
hidpp_device_init(&base, device->hidraw.fd);
hidpp_device_init(&base, device->hidraw[0].fd);
hidpp_device_set_log_handler(&base, hidpp20_log, HIDPP_LOG_PRIORITY_RAW, device);
device_idx = ratbag_device_data_hidpp20_get_index(device->data);
@@ -1335,7 +1339,7 @@ hidpp20drv_probe(struct ratbag_device *device)
drv_data->num_profiles = 1;
drv_data->num_resolutions = 1;
drv_data->num_buttons = 8;
drv_data->num_leds = 2;
drv_data->num_leds = 0;
rc = hidpp20drv_20_probe(device);
if (rc)

671
src/driver-logitech-g600.c Normal file
View File

@@ -0,0 +1,671 @@
/*
* Copyright © 2018 Thomas Hindoe Paaboel Andersen.
*
* 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 <libevdev/libevdev.h>
#include <linux/input.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "libratbag-private.h"
#include "libratbag-hidraw.h"
#define LOGITECH_G600_NUM_PROFILES 3
#define LOGITECH_G600_NUM_BUTTONS 20
#define LOGITECH_G600_NUM_DPI 4
#define LOGITECH_G600_NUM_LED 1
#define LOGITECH_G600_DPI_MIN 200
#define LOGITECH_G600_DPI_MAX 8200
#define LOGITECH_G600_REPORT_ID_GET_ACTIVE 0xF0
#define LOGITECH_G600_REPORT_ID_SET_ACTIVE 0xF0
#define LOGITECH_G600_REPORT_ID_PROFILE_0 0xF3
#define LOGITECH_G600_REPORT_ID_PROFILE_1 0xF4
#define LOGITECH_G600_REPORT_ID_PROFILE_2 0xF5
#define LOGITECH_G600_REPORT_SIZE_PROFILE 154
#define LOGITECH_G600_LED_SOLID 0x00
#define LOGITECH_G600_LED_BREATHE 0x01
#define LOGITECH_G600_LED_CYCLE 0x02
struct logitech_g600_button {
uint8_t code;
uint8_t modifier;
uint8_t key;
} __attribute__((packed));
struct logitech_g600_profile_report {
uint8_t id;
uint8_t led_red;
uint8_t led_green;
uint8_t led_blue;
uint8_t led_effect;
uint8_t led_duration;
uint8_t unknown1[5];
uint8_t frequency; /* frequency = 1000 / (value + 1) */
uint8_t dpi_shift; /* value is a linear range between 200->0x04, 8200->0xa4, so value * 50, 0x00 is disabled */
uint8_t dpi_default; /* between 1 and 4*/
uint8_t dpi[4]; /* value is a linear range between 200->0x04, 8200->0xa4, so value * 50, 0x00 is disabled */
uint8_t unknown2[13];
struct logitech_g600_button buttons[20];
uint8_t g_shift_color[3]; /* can't assign it in LGS, but the 3rd profile has one that shows the feature :) */
struct logitech_g600_button g_shift_buttons[20];
} __attribute__((packed));
struct logitech_g600_active_profile_report {
uint8_t id;
uint8_t unknown1 :1;
uint8_t resolution :2;
uint8_t unknown2 :1;
uint8_t profile :4;
uint8_t unknown3;
uint8_t unknown4;
} __attribute__((packed));
struct logitech_g600_profile_data {
struct logitech_g600_profile_report report;
};
struct logitech_g600_data {
struct logitech_g600_profile_data profile_data[LOGITECH_G600_NUM_PROFILES];
};
_Static_assert(sizeof(struct logitech_g600_profile_report) == LOGITECH_G600_REPORT_SIZE_PROFILE,
"Size of logitech_g600_profile_report is wrong");
struct logitech_g600_button_type_mapping {
uint8_t raw;
enum ratbag_button_type type;
};
static const struct logitech_g600_button_type_mapping logitech_g600_button_type_mapping[] = {
{ 0, RATBAG_BUTTON_TYPE_LEFT },
{ 1, RATBAG_BUTTON_TYPE_RIGHT },
{ 2, RATBAG_BUTTON_TYPE_MIDDLE },
{ 3, RATBAG_BUTTON_TYPE_WHEEL_LEFT },
{ 4, RATBAG_BUTTON_TYPE_WHEEL_RIGHT },
{ 5, RATBAG_BUTTON_TYPE_PINKIE },
{ 6, RATBAG_BUTTON_TYPE_PROFILE_CYCLE_UP },
{ 7, RATBAG_BUTTON_TYPE_RESOLUTION_CYCLE_UP },
{ 8, RATBAG_BUTTON_TYPE_SIDE }, // 8 = G9 ... 19 = G20
{ 9, RATBAG_BUTTON_TYPE_SIDE },
{ 10, RATBAG_BUTTON_TYPE_SIDE },
{ 11, RATBAG_BUTTON_TYPE_SIDE },
{ 12, RATBAG_BUTTON_TYPE_SIDE },
{ 13, RATBAG_BUTTON_TYPE_SIDE },
{ 14, RATBAG_BUTTON_TYPE_SIDE },
{ 15, RATBAG_BUTTON_TYPE_SIDE },
{ 16, RATBAG_BUTTON_TYPE_SIDE },
{ 17, RATBAG_BUTTON_TYPE_SIDE },
{ 18, RATBAG_BUTTON_TYPE_SIDE },
{ 19, RATBAG_BUTTON_TYPE_SIDE },
};
static enum ratbag_button_type
logitech_g600_raw_to_button_type(uint8_t data)
{
const struct logitech_g600_button_type_mapping *mapping;
ARRAY_FOR_EACH(logitech_g600_button_type_mapping, mapping) {
if (mapping->raw == data)
return mapping->type;
}
return RATBAG_BUTTON_TYPE_UNKNOWN;
}
struct logitech_g600_button_mapping {
uint8_t raw;
struct ratbag_button_action action;
};
static struct logitech_g600_button_mapping logitech_g600_button_mapping[] = {
/* 0x00 is either key or unassigned. Must be handled separatly */
{ 0x01, BUTTON_ACTION_BUTTON(1) },
{ 0x02, BUTTON_ACTION_BUTTON(2) },
{ 0x03, BUTTON_ACTION_BUTTON(3) },
{ 0x04, BUTTON_ACTION_BUTTON(4) },
{ 0x05, BUTTON_ACTION_BUTTON(5) },
{ 0x11, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_UP) },
{ 0x12, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_DOWN) },
{ 0x13, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_CYCLE_UP) },
{ 0x14, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_PROFILE_CYCLE_UP) },
{ 0x15, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_RESOLUTION_ALTERNATE) },
{ 0x17, BUTTON_ACTION_SPECIAL(RATBAG_BUTTON_ACTION_SPECIAL_SECOND_MODE) },
};
static const struct ratbag_button_action*
logitech_g600_raw_to_button_action(uint8_t data)
{
struct logitech_g600_button_mapping *mapping;
ARRAY_FOR_EACH(logitech_g600_button_mapping, mapping) {
if (mapping->raw == data)
return &mapping->action;
}
return NULL;
}
static uint8_t logitech_g600_modifier_to_raw(int modifier_flags)
{
uint8_t modifiers = 0x00;
if (modifier_flags & MODIFIER_LEFTCTRL)
modifiers |= 0x01;
if (modifier_flags & MODIFIER_LEFTSHIFT)
modifiers |= 0x02;
if (modifier_flags & MODIFIER_LEFTALT)
modifiers |= 0x04;
if (modifier_flags & MODIFIER_LEFTMETA)
modifiers |= 0x08;
if (modifier_flags & MODIFIER_RIGHTCTRL)
modifiers |= 0x10;
if (modifier_flags & MODIFIER_RIGHTSHIFT)
modifiers |= 0x20;
if (modifier_flags & MODIFIER_RIGHTALT)
modifiers |= 0x40;
if (modifier_flags & MODIFIER_RIGHTMETA)
modifiers |= 0x80;
return modifiers;
}
static int logitech_g600_raw_to_modifiers(uint8_t data)
{
int modifiers = 0;
if (data & 0x01)
modifiers |= MODIFIER_LEFTCTRL;
if (data & 0x02)
modifiers |= MODIFIER_LEFTSHIFT;
if (data & 0x04)
modifiers |= MODIFIER_LEFTALT;
if (data & 0x08)
modifiers |= MODIFIER_LEFTMETA;
if (data & 0x10)
modifiers |= MODIFIER_RIGHTCTRL;
if (data & 0x20)
modifiers |= MODIFIER_RIGHTSHIFT;
if (data & 0x40)
modifiers |= MODIFIER_RIGHTALT;
if (data & 0x80)
modifiers |= MODIFIER_RIGHTMETA;
return modifiers;
}
static uint8_t
logitech_g600_button_action_to_raw(const struct ratbag_button_action *action)
{
struct logitech_g600_button_mapping *mapping;
ARRAY_FOR_EACH(logitech_g600_button_mapping, mapping) {
if (ratbag_button_action_match(&mapping->action, action))
return mapping->raw;
}
return 0;
}
static int
logitech_g600_get_active_profile_and_resolution(struct ratbag_device *device)
{
struct ratbag_profile *profile;
struct logitech_g600_active_profile_report buf;
int ret;
ret = ratbag_hidraw_raw_request(device, LOGITECH_G600_REPORT_ID_GET_ACTIVE,
(uint8_t*)&buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0)
return ret;
if (ret != sizeof(buf))
return -EIO;
list_for_each(profile, &device->profiles, link) {
struct ratbag_resolution *resolution;
if (profile->index != buf.profile)
continue;
profile->is_active = true;
ratbag_profile_for_each_resolution(profile, resolution) {
resolution->is_active = resolution->index == buf.resolution;
}
}
return 0;
}
static int
logitech_g600_set_current_resolution(struct ratbag_device *device, unsigned int index)
{
uint8_t buf[] = {LOGITECH_G600_REPORT_ID_SET_ACTIVE, 0x40 | (index << 1), 0x00, 0x00};
int ret;
log_debug(device->ratbag, "Setting active resolution to %d\n", index);
if (index >= LOGITECH_G600_NUM_DPI)
return -EINVAL;
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret == sizeof(buf) ? 0 : ret;
}
static int
logitech_g600_set_active_profile(struct ratbag_device *device, unsigned int index)
{
struct ratbag_profile *profile;
uint8_t buf[] = {LOGITECH_G600_REPORT_ID_SET_ACTIVE, 0x80 | (index << 4), 0x00, 0x00};
int ret, active_resolution = 0;
if (index >= LOGITECH_G600_NUM_PROFILES)
return -EINVAL;
ret = ratbag_hidraw_raw_request(device, buf[0], buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != sizeof(buf))
return ret;
/* Update the active resolution. After profile change the default is used. */
list_for_each(profile, &device->profiles, link) {
struct ratbag_resolution *resolution;
if (profile->index != index)
continue;
ratbag_profile_for_each_resolution(profile, resolution) {
resolution->is_active = resolution->is_default;
if (resolution->is_active)
active_resolution = resolution->index;
}
}
ret = logitech_g600_set_current_resolution(device, active_resolution);
if (ret < 0)
return ret;
return 0;
}
static void
logitech_g600_read_button(struct ratbag_button *button)
{
const struct ratbag_button_action *action;
struct ratbag_profile *profile = button->profile;
struct ratbag_device *device = profile->device;
struct logitech_g600_data *drv_data = device->drv_data;
struct logitech_g600_profile_data *pdata;
struct logitech_g600_profile_report *profile_report;
struct logitech_g600_button *button_report;
pdata = &drv_data->profile_data[profile->index];
profile_report = &pdata->report;
button_report = &profile_report->buttons[button->index];
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
button->type = logitech_g600_raw_to_button_type(button->index);
action = logitech_g600_raw_to_button_action(button_report->code);
if (action) {
ratbag_button_set_action(button, action);
}
else if (button_report->code == 0x00 && (button_report->modifier > 0x00 || button_report->key > 0x00))
{
unsigned int key, modifiers;
int rc;
key = ratbag_hidraw_get_keycode_from_keyboard_usage(device,
button_report->key);
modifiers = logitech_g600_raw_to_modifiers(button_report->modifier);
rc = ratbag_button_macro_new_from_keycode(button, key, modifiers);
if (rc < 0) {
log_error(device->ratbag,
"Error while reading button %d\n",
button->index);
button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE;
}
}
}
static void
logitech_g600_read_led(struct ratbag_led *led)
{
struct ratbag_profile *profile = led->profile;
struct ratbag_device *device = profile->device;
struct logitech_g600_data *drv_data = device->drv_data;
struct logitech_g600_profile_data *pdata;
struct logitech_g600_profile_report *report;
pdata = &drv_data->profile_data[profile->index];
report = &pdata->report;
led->type = RATBAG_LED_TYPE_SIDE;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
ratbag_led_set_mode_capability(led, RATBAG_LED_CYCLE);
switch (report->led_effect) {
case LOGITECH_G600_LED_SOLID:
led->mode = RATBAG_LED_ON;
break;
case LOGITECH_G600_LED_BREATHE:
led->mode = RATBAG_LED_BREATHING;
led->ms = report->led_duration * 1000;
break;
case LOGITECH_G600_LED_CYCLE:
led->mode = RATBAG_LED_CYCLE;
led->ms = report->led_duration * 1000;
break;
}
led->color.red = report->led_red;
led->color.green = report->led_green;
led->color.blue = report->led_blue;
}
static void
logitech_g600_read_profile(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct logitech_g600_data *drv_data = device->drv_data;
struct logitech_g600_profile_data *pdata;
struct logitech_g600_profile_report *report;
struct ratbag_resolution *resolution;
unsigned int report_rates[] = { 125, 142, 166, 200, 250, 333, 500, 1000 };
uint8_t report_id;
int rc;
struct ratbag_button *button;
struct ratbag_led *led;
assert(profile->index < LOGITECH_G600_NUM_PROFILES);
pdata = &drv_data->profile_data[profile->index];
report = &pdata->report;
switch (profile->index) {
case 0: report_id = LOGITECH_G600_REPORT_ID_PROFILE_0; break;
case 1: report_id = LOGITECH_G600_REPORT_ID_PROFILE_1; break;
case 2: report_id = LOGITECH_G600_REPORT_ID_PROFILE_2; break;
}
rc = ratbag_hidraw_raw_request(device, report_id,
(uint8_t*)report,
sizeof(*report),
HID_FEATURE_REPORT,
HID_REQ_GET_REPORT);
if (rc < (int)sizeof(*report)) {
log_error(device->ratbag,
"Error while requesting profile: %d\n", rc);
return;
}
ratbag_profile_for_each_resolution(profile, resolution) {
resolution->dpi_x = report->dpi[resolution->index] * 50;
resolution->dpi_y = report->dpi[resolution->index] * 50;
resolution->hz = 1000 / (report->frequency + 1);
resolution->is_default = report->dpi_default - 1U == resolution->index;
resolution->is_active = resolution->is_default;
ratbag_resolution_set_dpi_list_from_range(resolution,
LOGITECH_G600_DPI_MIN,
LOGITECH_G600_DPI_MAX);
ratbag_resolution_set_report_rate_list(resolution, report_rates,
ARRAY_LENGTH(report_rates));
}
ratbag_profile_for_each_button(profile, button)
logitech_g600_read_button(button);
ratbag_profile_for_each_led(profile, led)
logitech_g600_read_led(led);
log_debug(device->ratbag, "Unknown data in profile %d\n", profile->index);
log_buf_debug(device->ratbag, " profile->unknown1: ",
report->unknown1, 5);
log_buf_debug(device->ratbag, " profile->unknown2: ",
report->unknown2, 13);
}
static int
logitech_g600_test_hidraw(struct ratbag_device *device)
{
return ratbag_hidraw_has_report(device, LOGITECH_G600_REPORT_ID_GET_ACTIVE);
}
static int
logitech_g600_probe(struct ratbag_device *device)
{
int rc;
struct logitech_g600_data *drv_data = NULL;
struct ratbag_profile *profile;
rc = ratbag_find_hidraw(device, logitech_g600_test_hidraw);
if (rc)
goto err;
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
ratbag_device_init_profiles(device,
LOGITECH_G600_NUM_PROFILES,
LOGITECH_G600_NUM_DPI,
LOGITECH_G600_NUM_BUTTONS,
LOGITECH_G600_NUM_LED);
ratbag_device_for_each_profile(device, profile)
logitech_g600_read_profile(profile);
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);
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
rc = logitech_g600_get_active_profile_and_resolution(device);
if (rc < 0) {
log_error(device->ratbag,
"Can't talk to the mouse: '%s' (%d)\n",
strerror(-rc),
rc);
rc = -ENODEV;
goto err;
}
return 0;
err:
free(drv_data);
ratbag_set_drv_data(device, NULL);
return rc;
}
static int
logitech_g600_write_profile(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
struct logitech_g600_data *drv_data = device->drv_data;
struct logitech_g600_profile_data *pdata;
struct logitech_g600_profile_report *report;
struct ratbag_resolution *resolution;
struct ratbag_button *button;
struct ratbag_led *led;
uint8_t *buf;
int rc, active_resolution = 0;
pdata = &drv_data->profile_data[profile->index];
report = &pdata->report;
ratbag_profile_for_each_resolution(profile, resolution) {
report->dpi[resolution->index] = resolution->dpi_x / 50;
if (resolution->is_default)
report->dpi_default = resolution->index + 1;
if (profile->is_active && resolution->is_active)
active_resolution = resolution->index;
/* The same hz is used for all resolutions */
if (resolution->index == 0)
report->frequency = (1000 / resolution->hz) - 1;
}
list_for_each(button, &profile->buttons, link) {
struct ratbag_button_action *action = &button->action;
struct logitech_g600_button *raw_button;
raw_button = &report->buttons[button->index];
raw_button->code = logitech_g600_button_action_to_raw(action);
raw_button->modifier = 0x00;
raw_button->key = 0x00;
if (action->type == RATBAG_BUTTON_ACTION_TYPE_MACRO) {
unsigned int key, modifiers;
rc = ratbag_action_keycode_from_macro(action,
&key,
&modifiers);
if (rc < 0) {
log_error(device->ratbag,
"Error while writing macro for button %d\n",
button->index);
}
raw_button->key = ratbag_hidraw_get_keyboard_usage_from_keycode(
device, key);
raw_button->modifier = logitech_g600_modifier_to_raw(modifiers);
}
}
list_for_each(led, &profile->leds, link) {
report->led_red = led->color.red;
report->led_green = led->color.green;
report->led_blue = led->color.blue;
switch (led->mode) {
case RATBAG_LED_ON:
report->led_effect = LOGITECH_G600_LED_SOLID;
break;
case RATBAG_LED_OFF:
report->led_effect = LOGITECH_G600_LED_SOLID;
report->led_red = 0x00;
report->led_green = 0x00;
report->led_blue = 0x00;
break;
case RATBAG_LED_BREATHING:
report->led_effect = LOGITECH_G600_LED_BREATHE;
report->led_duration = led->ms / 1000;
break;
case RATBAG_LED_CYCLE:
report->led_effect = LOGITECH_G600_LED_CYCLE;
report->led_duration = led->ms / 1000;
break;
}
if (report->led_duration > 0x0f)
report->led_duration = 0x0f;
}
buf = (uint8_t*)report;
rc = ratbag_hidraw_raw_request(device, report->id,
buf,
sizeof(*report),
HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
if (rc < (int)sizeof(*report)) {
log_error(device->ratbag,
"Error while writing profile: %d\n", rc);
return rc;
}
if (profile->is_active) {
rc = logitech_g600_set_current_resolution(device, active_resolution);
if (rc < 0)
return rc;
}
return 0;
}
static int
logitech_g600_commit(struct ratbag_device *device)
{
struct ratbag_profile *profile;
int rc = 0;
list_for_each(profile, &device->profiles, link) {
if (!profile->dirty)
continue;
log_debug(device->ratbag,
"Profile %d changed, rewriting\n", profile->index);
rc = logitech_g600_write_profile(profile);
if (rc)
return rc;
}
return 0;
}
static void
logitech_g600_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
free(ratbag_get_drv_data(device));
}
struct ratbag_driver logitech_g600_driver = {
.name = "Logitech G600",
.id = "logitech_g600",
.probe = logitech_g600_probe,
.remove = logitech_g600_remove,
.commit = logitech_g600_commit,
.set_active_profile = logitech_g600_set_active_profile,
};

View File

@@ -37,6 +37,8 @@
#define STEELSERIES_NUM_PROFILES 1
#define STEELSERIES_NUM_DPI 2
#define STEELSERIES_INPUT_ENDPOINT 0
#define STEELSERIES_INPUT_HIDRAW 1
/* not sure these two are used for */
#define STEELSERIES_REPORT_ID_1 0x01
@@ -48,6 +50,7 @@
#define STEELSERIES_ID_DPI_SHORT 0x03
#define STEELSERIES_ID_REPORT_RATE_SHORT 0x04
#define STEELSERIES_ID_LED_INTENSITY_SHORT 0x05
#define STEELSERIES_ID_LED_EFFECT_SHORT 0x07
#define STEELSERIES_ID_LED_COLOR_SHORT 0x08
#define STEELSERIES_ID_SAVE_SHORT 0x09
@@ -57,14 +60,37 @@
#define STEELSERIES_ID_REPORT_RATE 0x54
#define STEELSERIES_ID_LED 0x5b
#define STEELSERIES_ID_SAVE 0x59
#define STEELSERIES_ID_FIRMWARE 0x90
#define STEELSERIES_ID_SETTTINGS 0x92
#define STEELSERIES_BUTTON_OFF 0x00
#define STEELSERIES_BUTTON_RES_CYCLE 0x30
#define STEELSERIES_BUTTON_WHEEL_UP 0x31
#define STEELSERIES_BUTTON_WHEEL_DOWN 0x32
#define STEELSERIES_BUTTON_KEY 0x10
#define STEELSERIES_BUTTON_KBD 0x51
#define STEELSERIES_BUTTON_CONSUMER 0x61
struct steelseries_data {
int firmware_major;
int firmware_minor;
};
struct steelseries_point {
struct list link;
struct ratbag_color color; /* point color */
uint8_t pos; /* relative position in the cycle */
};
struct steelseries_led_cycle {
uint8_t led_id; /* led id */
uint16_t duration; /* cycle duration */
bool repeat; /* if the cycle restarts automatically */
uint8_t trigger_buttons; /* trigger button combination */
struct list points; /* colors in the cycle */
};
static int
steelseries_test_hidraw(struct ratbag_device *device)
{
@@ -120,14 +146,88 @@ button_defaults_for_layout(struct ratbag_button *button, int button_count)
ratbag_button_set_action(button, &button_actions[button->index]);
}
static int
steelseries_get_firmware_version(struct ratbag_device *device)
{
struct steelseries_data *drv_data = device->drv_data;
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
size_t buf_len = STEELSERIES_REPORT_SIZE;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
int ret;
if (device_version == 1)
return 0;
buf[0] = STEELSERIES_ID_FIRMWARE;
msleep(10);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, buf_len, STEELSERIES_INPUT_HIDRAW);
if (ret < 0)
return ret;
drv_data->firmware_major = buf[1];
drv_data->firmware_minor = buf[0];
return 0;
}
static int
steelseries_read_settings(struct ratbag_device *device)
{
int device_version = ratbag_device_data_steelseries_get_device_version(device->data);
struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution;
struct ratbag_led *led;
size_t buf_len = STEELSERIES_REPORT_SIZE;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
int ret;
unsigned int active_resolution;
if (device_version == 1)
return 0;
buf[0] = STEELSERIES_ID_SETTTINGS;
msleep(10);
ret = ratbag_hidraw_output_report(device, buf, buf_len);
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, buf_len, STEELSERIES_INPUT_HIDRAW);
if (ret < 0)
return ret;
active_resolution = buf[1] - 1;
ratbag_device_for_each_profile(device, profile) {
ratbag_profile_for_each_resolution(profile, resolution) {
resolution->is_active = resolution->index == active_resolution;
resolution->dpi_x = 100 * (1 + buf[2 + resolution->index*2]);
resolution->dpi_y = resolution->dpi_x;
}
ratbag_profile_for_each_led(profile, led) {
led->color.red = buf[6 + led->index * 3];
led->color.green = buf[7 + led->index * 3];
led->color.blue = buf[8 + led->index * 3];
}
}
return 0;
}
static int
steelseries_probe(struct ratbag_device *device)
{
struct steelseries_data *drv_data = NULL;
struct ratbag_profile *profile = NULL;
struct ratbag_resolution *resolution;
struct ratbag_button *button;
struct ratbag_led *led;
int rc, button_count, led_count, device_version;
int rc, button_count, led_count, device_version, mono_led, short_button;
_cleanup_(dpi_list_freep) struct dpi_list *dpilist = NULL;
_cleanup_(freep) struct dpi_range *dpirange = NULL;
@@ -137,11 +237,19 @@ steelseries_probe(struct ratbag_device *device)
if (rc)
return rc;
rc = ratbag_open_hidraw_index(device,
STEELSERIES_INPUT_ENDPOINT,
STEELSERIES_INPUT_HIDRAW);
if (rc)
return rc;
device_version = ratbag_device_data_steelseries_get_device_version(device->data);
button_count = ratbag_device_data_steelseries_get_button_count(device->data);
led_count = ratbag_device_data_steelseries_get_led_count(device->data);
dpirange = ratbag_device_data_steelseries_get_dpi_range(device->data);
dpilist = ratbag_device_data_steelseries_get_dpi_list(device->data);
mono_led = ratbag_device_data_steelseries_get_mono_led(device->data);
short_button = ratbag_device_data_steelseries_get_short_button(device->data);
ratbag_device_init_profiles(device,
STEELSERIES_NUM_PROFILES,
@@ -154,7 +262,9 @@ steelseries_probe(struct ratbag_device *device)
/* set these caps manually as they are not assumed with only 1 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);
if (short_button == 0) {
ratbag_device_set_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS);
}
}
ratbag_device_unset_capability(device, RATBAG_DEVICE_CAP_QUERY_CONFIGURATION);
@@ -193,7 +303,9 @@ steelseries_probe(struct ratbag_device *device)
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY);
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
if (short_button == 0) {
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO);
}
button_defaults_for_layout(button, button_count);
}
@@ -201,10 +313,15 @@ steelseries_probe(struct ratbag_device *device)
ratbag_profile_for_each_led(profile, led) {
led->type = led->index == 0 ? RATBAG_LED_TYPE_LOGO : RATBAG_LED_TYPE_WHEEL;
led->mode = RATBAG_LED_ON;
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
led->color.red = 0;
led->color.green = 0;
led->color.blue = 255;
if (mono_led) {
led->colordepth = RATBAG_LED_COLORDEPTH_MONOCHROME;
led->brightness = 255;
} else {
led->colordepth = RATBAG_LED_COLORDEPTH_RGB_888;
led->color.red = 0;
led->color.green = 0;
led->color.blue = 255;
}
ratbag_led_set_mode_capability(led, RATBAG_LED_OFF);
ratbag_led_set_mode_capability(led, RATBAG_LED_ON);
ratbag_led_set_mode_capability(led, RATBAG_LED_BREATHING);
@@ -213,6 +330,16 @@ steelseries_probe(struct ratbag_device *device)
}
}
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);
steelseries_get_firmware_version(device);
log_debug(device->ratbag, "SteelSeries firmware version %d.%d\n",
drv_data->firmware_major,
drv_data->firmware_minor);
steelseries_read_settings(device);
return 0;
}
@@ -295,13 +422,20 @@ static int
steelseries_write_buttons(struct ratbag_profile *profile)
{
struct ratbag_device *device = profile->device;
uint8_t buf[STEELSERIES_REPORT_LONG_SIZE] = {0};
struct ratbag_button *button;
int ret;
if (ratbag_device_data_steelseries_get_macro_length(device->data) == 0)
return 0;
int short_button = ratbag_device_data_steelseries_get_short_button(device->data);
int button_size = (short_button == 0) ? 5 : 3;
int report_size = (short_button == 0) ? STEELSERIES_REPORT_LONG_SIZE : STEELSERIES_REPORT_SIZE_SHORT;
int max_modifiers = (short_button == 0) ? 3 : 0;
uint8_t buf[report_size];
memset(buf, 0, report_size);
buf[0] = STEELSERIES_ID_BUTTONS;
ratbag_profile_for_each_button(profile, button) {
@@ -310,8 +444,8 @@ steelseries_write_buttons(struct ratbag_profile *profile)
unsigned int key, modifiers;
int idx;
/* Each button takes up 5 bytes starting from index 2 */
idx = 2 + button->index * 5;
/* Each button takes up 3 or 5 bytes starting from index 2 */
idx = 2 + button->index * button_size;
switch (action->type) {
case RATBAG_BUTTON_ACTION_TYPE_BUTTON:
@@ -322,34 +456,38 @@ steelseries_write_buttons(struct ratbag_profile *profile)
ratbag_action_keycode_from_macro(action, &key, &modifiers);
/* There is only space for 3 modifiers */
if (__builtin_popcount(modifiers > 3)) {
log_debug(device->ratbag,
"Too many modifiers in macro for button %d\n",
button->index);
if (__builtin_popcount(modifiers) > max_modifiers) {
log_error(device->ratbag,
"Too many modifiers in macro for button %d (maximum %d)\n",
button->index, max_modifiers);
break;
}
code = ratbag_hidraw_get_keyboard_usage_from_keycode(
device, key);
if (code) {
buf[idx] = STEELSERIES_BUTTON_KBD;
if (short_button) {
buf[idx] = STEELSERIES_BUTTON_KEY;
} else {
buf[idx] = STEELSERIES_BUTTON_KBD;
if (modifiers & MODIFIER_LEFTCTRL)
buf[++idx] = 0xE0;
if (modifiers & MODIFIER_LEFTSHIFT)
buf[++idx] = 0xE1;
if (modifiers & MODIFIER_LEFTALT)
buf[++idx] = 0xE2;
if (modifiers & MODIFIER_LEFTMETA)
buf[++idx] = 0xE3;
if (modifiers & MODIFIER_RIGHTCTRL)
buf[++idx] = 0xE4;
if (modifiers & MODIFIER_RIGHTSHIFT)
buf[++idx] = 0xE5;
if (modifiers & MODIFIER_RIGHTALT)
buf[++idx] = 0xE6;
if (modifiers & MODIFIER_RIGHTMETA)
buf[++idx] = 0xE7;
if (modifiers & MODIFIER_LEFTCTRL)
buf[++idx] = 0xE0;
if (modifiers & MODIFIER_LEFTSHIFT)
buf[++idx] = 0xE1;
if (modifiers & MODIFIER_LEFTALT)
buf[++idx] = 0xE2;
if (modifiers & MODIFIER_LEFTMETA)
buf[++idx] = 0xE3;
if (modifiers & MODIFIER_RIGHTCTRL)
buf[++idx] = 0xE4;
if (modifiers & MODIFIER_RIGHTSHIFT)
buf[++idx] = 0xE5;
if (modifiers & MODIFIER_RIGHTALT)
buf[++idx] = 0xE6;
if (modifiers & MODIFIER_RIGHTMETA)
buf[++idx] = 0xE7;
}
buf[idx + 1] = code;
} else {
@@ -421,11 +559,24 @@ steelseries_write_led_v1(struct ratbag_led *led)
if (ret < 0)
return ret;
buf[0] = STEELSERIES_ID_LED_COLOR_SHORT;
buf[1] = led->index + 1;
buf[2] = led->color.red;
buf[3] = led->color.green;
buf[4] = led->color.blue;
int mono_led = ratbag_device_data_steelseries_get_mono_led(device->data);
if (mono_led) {
buf[0] = STEELSERIES_ID_LED_INTENSITY_SHORT;
buf[1] = led->index + 1;
if (led->mode == RATBAG_LED_OFF || led->brightness == 0) {
buf[2] = 1;
} else {
//split the brightness into roughly 3 equal intensities
buf[2] = (led->brightness / 86) + 2;
}
} else {
buf[0] = STEELSERIES_ID_LED_COLOR_SHORT;
buf[1] = led->index + 1;
buf[2] = led->color.red;
buf[3] = led->color.green;
buf[4] = led->color.blue;
}
msleep(10);
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
@@ -435,103 +586,134 @@ steelseries_write_led_v1(struct ratbag_led *led)
return 0;
}
static void
create_cycle(struct steelseries_led_cycle *cycle)
{
cycle->led_id = 0x00;
cycle->duration = 5000;
cycle->repeat = true;
cycle->trigger_buttons = 0x00;
list_init(&cycle->points);
}
static void
construct_cycle_buffer(struct steelseries_led_cycle *cycle, uint8_t *buf, uint8_t buf_size)
{
struct steelseries_point *point;
uint16_t duration;
uint8_t npoints = 0;
uint16_t cycle_size = 0;
buf[0] = STEELSERIES_ID_LED;
buf[2] = cycle->led_id;
if (!cycle->repeat)
buf[19] = 0x01;
buf[23] = cycle->trigger_buttons;
list_for_each(point, &cycle->points, link) {
if(npoints == 0){
/* this is not a mistake,
we need to write the first
point to 28,29,30 */
buf[28] = point->color.red;
buf[29] = point->color.green;
buf[30] = point->color.blue;
}
cycle_size += point->pos;
assert(cycle_size < 256);
assert(34 + npoints*4 <= buf_size);
buf[31 + npoints*4] = point->color.red;
buf[32 + npoints*4] = point->color.green;
buf[33 + npoints*4] = point->color.blue;
buf[34 + npoints*4] = point->pos;
npoints++;
}
buf[27] = npoints;
/* this seems to be the minimum allowed */
duration = max(buf[27] * 330, cycle->duration);
hidpp_set_unaligned_le_u16(&buf[3], duration);
}
static int
steelseries_write_led_v2(struct ratbag_led *led)
{
struct ratbag_device *device = led->profile->device;
uint8_t buf[STEELSERIES_REPORT_SIZE] = {0};
uint16_t duration, min_duration;
int ret;
buf[0] = STEELSERIES_ID_LED;
buf[2] = led->index;
struct steelseries_led_cycle cycle;
struct steelseries_point point[4];
/* not sure if these two are needed */
buf[15] = 0x01;
buf[17] = 0x01;
const struct ratbag_color black = { 0x00 };
const struct ratbag_color red = { 0xFF, 0x00, 0x00 };
const struct ratbag_color green = { 0x00, 0xFF, 0x00 };
const struct ratbag_color blue = { 0x00, 0x00, 0xFF };
create_cycle(&cycle);
cycle.led_id = led->index;
switch(led->mode) {
case RATBAG_LED_OFF:
buf[19] = 0x01;
buf[27] = 0x01;
buf[28] = buf[31] = 0x00;
buf[29] = buf[32] = 0x00;
buf[30] = buf[33] = 0x00;
/* not sure why the duration is set for the steady color or why
it is different for the two LEDs */
duration = led->index == 0 ? 10000 : 5000; /* 0x1027 or 0x8813 */
point[0].color = black;
point[0].pos = 0x00;
list_append(&cycle.points, &point[0].link);
break;
case RATBAG_LED_ON:
buf[19] = 0x01;
buf[27] = 0x01;
buf[28] = buf[31] = led->color.red;
buf[29] = buf[32] = led->color.green;
buf[30] = buf[33] = led->color.blue;
point[0].color = led->color;
/* not sure why the duration is set for the steady color or why
it is different for the two LEDs */
duration = led->index == 0 ? 10000 : 5000; /* 0x1027 or 0x8813 */
list_append(&cycle.points, &point[0].link);
break;
case RATBAG_LED_CYCLE:
buf[27] = 0x04; /* number of steps in cycle */
case RATBAG_LED_CYCLE:
point[0].color = red;
point[0].pos = 0x00;
/* start color */
buf[28] = buf[31] = 0xFF;
buf[29] = buf[32] = 0x00;
buf[30] = buf[33] = 0x00;
point[1].color = green;
point[1].pos = 0x55;
/* Cycle to green */
buf[35] = 0x00;
buf[36] = 0xFF;
buf[37] = 0x00;
buf[38] = 0x54; /* normalized time share of animation */
point[2].color = blue;
point[2].pos = 0x55;
/* Cycle to blue */
buf[39] = 0x00;
buf[40] = 0x00;
buf[41] = 0xFF;
buf[42] = 0x54; /* normalized time share of animation */
point[3].color = red;
point[3].pos = 0x55;
/* Cycle to red */
buf[43] = 0xFF;
buf[44] = 0x00;
buf[45] = 0x00;
buf[46] = 0x56; /* normalized time share of animation */
list_append(&cycle.points, &point[0].link);
list_append(&cycle.points, &point[1].link);
list_append(&cycle.points, &point[2].link);
list_append(&cycle.points, &point[3].link);
duration = led->ms;
cycle.duration = led->ms;
break;
case RATBAG_LED_BREATHING:
buf[27] = 0x03; /* number of steps in cycle */
point[0].color = black;
point[0].pos = 0x00;
/* start color */
buf[28] = buf[31] = led->color.red;
buf[29] = buf[32] = led->color.green;
buf[30] = buf[33] = led->color.blue;
point[1].color = led->color;
point[1].pos = 0x7F;
/* Cycle to black */
buf[35] = 0x00;
buf[36] = 0x00;
buf[37] = 0x00;
buf[38] = 0x7F; /* normalized time share of animation */
point[2].color = black;
point[2].pos = 0x7F;
list_append(&cycle.points, &point[0].link);
list_append(&cycle.points, &point[1].link);
list_append(&cycle.points, &point[2].link);
/* Cycle to selected color */
buf[39] = led->color.red;
buf[40] = led->color.green;
buf[41] = led->color.blue;
buf[42] = 0x7F; /* normalized time share of animation */
duration = led->ms;
cycle.duration = led->ms;
break;
default:
return -EINVAL;
}
/* this seems to be the minimum allowed */
min_duration = buf[27] * 330;
if (duration < min_duration)
duration = min_duration;
hidpp_set_unaligned_le_u16(&buf[3], duration);
construct_cycle_buffer(&cycle, buf, sizeof(buf));
msleep(10);
ret = ratbag_hidraw_output_report(device, buf, sizeof(buf));
@@ -658,7 +840,9 @@ steelseries_commit(struct ratbag_device *device)
static void
steelseries_remove(struct ratbag_device *device)
{
ratbag_close_hidraw(device);
ratbag_close_hidraw_index(device, 0);
ratbag_close_hidraw_index(device, 1);
free(ratbag_get_drv_data(device));
}
struct ratbag_driver steelseries_driver = {

View File

@@ -190,7 +190,7 @@ test_read_profile(struct ratbag_profile *profile)
r0 = &p0->resolutions[0];
for (i = 0; i < d->num_resolutions; i++) {
_cleanup_resolution_ struct ratbag_resolution *res;
_cleanup_resolution_ struct ratbag_resolution *res = NULL;
size_t nrates = 0;
r = &p->resolutions[i];
@@ -225,7 +225,7 @@ test_read_profile(struct ratbag_profile *profile)
/* special case triggered by the test suite when num_resolutions is 0 */
if (d->num_resolutions) {
_cleanup_resolution_ struct ratbag_resolution *res;
_cleanup_resolution_ struct ratbag_resolution *res = NULL;
res = ratbag_profile_get_resolution(profile, 0);
assert(res);

View File

@@ -2362,7 +2362,7 @@ hidpp20_onboard_profiles_parse(struct hidpp20_device *device,
profiles->sector_size,
data);
if (rc < 0)
return rc;
return rc; // ignore_clang_sa_mem_leak
crc_valid = hidpp20_onboard_profiles_is_sector_valid(device,
profiles->sector_size,

View File

@@ -195,7 +195,7 @@ lur_receiver_enumerate(struct lur_receiver *lur,
dev->present = false;
for (i = 0; i < MAX_DEVICES; i++) {
_cleanup_hidpp10_device_destroy_ struct hidpp10_device *d;
_cleanup_hidpp10_device_destroy_ struct hidpp10_device *d = NULL;
size_t name_size = 64;
char name[name_size];
uint8_t interval, type;

View File

@@ -28,6 +28,7 @@
#include <assert.h>
#include <stdlib.h>
#include <glib.h>
#include <limits.h>
#include "libratbag.h"
#include "libratbag-private.h"
@@ -47,6 +48,7 @@ enum driver {
ETEKCITY,
GSKILL,
LOGITECH_G300,
LOGITECH_G600,
STEELSERIES,
};
@@ -71,6 +73,8 @@ struct data_steelseries {
struct dpi_list *dpi_list;
struct dpi_range *dpi_range;
int macro_length;
int mono_led;
int short_button;
};
struct ratbag_device_data {
@@ -174,6 +178,8 @@ init_data_steelseries(struct ratbag *ratbag,
data->steelseries.led_count = -1;
data->steelseries.dpi_list = NULL;
data->steelseries.dpi_range = NULL;
data->steelseries.mono_led = 0;
data->steelseries.short_button = 0;
num = g_key_file_get_integer(keyfile, group, "Buttons", &error);
if (num != 0 || !error)
@@ -210,6 +216,20 @@ init_data_steelseries(struct ratbag *ratbag,
data->steelseries.macro_length = num;
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "MonoLed", &error);
if (num > 0 || !error)
data->steelseries.mono_led = num;
if (error)
g_error_free(error);
error = NULL;
num = g_key_file_get_integer(keyfile, group, "ShortButton", &error);
if (num > 0 || !error)
data->steelseries.short_button = num;
if (error)
g_error_free(error);
}
static const struct driver_map {
@@ -225,6 +245,7 @@ static const struct driver_map {
{ ETEKCITY, "etekcity", NULL},
{ GSKILL, "gskill", NULL },
{ LOGITECH_G300, "logitech_g300", NULL},
{ LOGITECH_G600, "logitech_g600", NULL},
{ STEELSERIES, "steelseries", init_data_steelseries },
};
@@ -388,7 +409,7 @@ file_data_matches(struct ratbag *ratbag,
data->refcount = 1;
data->name = g_key_file_get_string(keyfile, GROUP_DEVICE, "Name", NULL);
if (!data->name) {
return false;
return false; // ignore_clang_sa_mem_leak
}
data->driver = g_key_file_get_string(keyfile, GROUP_DEVICE, "Driver", NULL);
@@ -599,3 +620,19 @@ ratbag_device_data_steelseries_get_macro_length(const struct ratbag_device_data
return data->steelseries.macro_length;
}
int
ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *data)
{
assert(data->drivertype == STEELSERIES);
return data->steelseries.mono_led;
}
int
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data)
{
assert(data->drivertype == STEELSERIES);
return data->steelseries.short_button;
}

View File

@@ -110,3 +110,9 @@ ratbag_device_data_steelseries_get_dpi_range(const struct ratbag_device_data *da
int
ratbag_device_data_steelseries_get_macro_length(const struct ratbag_device_data *data);
int
ratbag_device_data_steelseries_get_mono_led(const struct ratbag_device_data *data);
int
ratbag_device_data_steelseries_get_short_button(const struct ratbag_device_data *data);

View File

@@ -1223,7 +1223,7 @@ static int
ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device)
{
int rc, desc_size = 0;
struct ratbag_hidraw *hidraw = &device->hidraw;
struct ratbag_hidraw *hidraw = &device->hidraw[0];
struct hidraw_report_descriptor report_desc = {0};
unsigned int i, j;
unsigned int usage_page, usage;
@@ -1291,7 +1291,7 @@ ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device)
}
static int
ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw_udev)
ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw_udev, int idx)
{
struct hidraw_devinfo info;
struct ratbag_device *tmp_device;
@@ -1300,15 +1300,17 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw
const char *sysname;
size_t reports_size;
device->hidraw.fd = -1;
assert(idx >= 0 && idx < MAX_HIDRAW);
device->hidraw[idx].fd = -1;
sysname = udev_device_get_sysname(hidraw_udev);
if (!strneq("hidraw", sysname, 6))
return -ENODEV;
list_for_each(tmp_device, &device->ratbag->devices, link) {
if (tmp_device->hidraw.sysname &&
streq(tmp_device->hidraw.sysname, sysname)) {
if (tmp_device->hidraw[idx].sysname &&
streq(tmp_device->hidraw[idx].sysname, sysname)) {
return -ENODEV;
}
}
@@ -1339,7 +1341,7 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw
device->name,
udev_device_get_devnode(hidraw_udev));
device->hidraw.fd = fd;
device->hidraw[idx].fd = fd;
/* parse first to count the number of reports */
res = ratbag_hidraw_parse_report_descriptor(device);
@@ -1348,19 +1350,19 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw
"Error while parsing the report descriptor: '%s' (%d)\n",
strerror(-res),
res);
device->hidraw.fd = -1;
device->hidraw[idx].fd = -1;
goto err;
}
if (device->hidraw.num_reports)
reports_size = device->hidraw.num_reports * sizeof(struct ratbag_hid_report);
if (device->hidraw[idx].num_reports)
reports_size = device->hidraw[idx].num_reports * sizeof(struct ratbag_hid_report);
else
reports_size = sizeof(struct ratbag_hid_report);
device->hidraw.reports = zalloc(reports_size);
device->hidraw[idx].reports = zalloc(reports_size);
ratbag_hidraw_parse_report_descriptor(device);
device->hidraw.sysname = strdup_safe(sysname);
device->hidraw[idx].sysname = strdup_safe(sysname);
return 0;
err:
@@ -1372,17 +1374,18 @@ err:
static int
ratbag_find_hidraw_node(struct ratbag_device *device,
int (*match)(struct ratbag_device *device),
int use_usb_parent)
int use_usb_parent,
int match_index, int hidraw_index)
{
struct ratbag *ratbag = device->ratbag;
struct udev_enumerate *e;
_cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
struct udev_list_entry *entry;
const char *path;
struct udev_device *hid_udev;
struct udev_device *parent_udev;
struct udev *udev = ratbag->udev;
int rc = -ENODEV;
int matched;
int matched, endpoint_index = 0;
assert(match);
@@ -1414,29 +1417,30 @@ ratbag_find_hidraw_node(struct ratbag_device *device,
if (!udev_device)
continue;
rc = ratbag_open_hidraw_node(device, udev_device);
if (match_index > 0 && match_index != endpoint_index++)
continue;
rc = ratbag_open_hidraw_node(device, udev_device, hidraw_index);
if (rc)
goto skip;
matched = match(device);
rc = matched ? 0 : -ENODEV;
if (matched == 1)
goto out;
return rc;
skip:
ratbag_close_hidraw(device);
ratbag_close_hidraw_index(device, hidraw_index);
}
out:
udev_enumerate_unref(e);
return rc;
}
int
ratbag_find_hidraw(struct ratbag_device *device, int (*match)(struct ratbag_device *device))
{
return ratbag_find_hidraw_node(device, match, true);
return ratbag_find_hidraw_node(device, match, true, -1, 0);
}
static int
@@ -1448,7 +1452,13 @@ hidraw_match_all(struct ratbag_device *device)
int
ratbag_open_hidraw(struct ratbag_device *device)
{
return ratbag_find_hidraw_node(device, hidraw_match_all, false);
return ratbag_find_hidraw_node(device, hidraw_match_all, false, -1, 0);
}
int
ratbag_open_hidraw_index(struct ratbag_device *device, int endpoint_index, int hidraw_index)
{
return ratbag_find_hidraw_node(device, hidraw_match_all, true, endpoint_index, hidraw_index);
}
static struct ratbag_hid_report *
@@ -1457,15 +1467,15 @@ ratbag_hidraw_get_report(struct ratbag_device *device, unsigned int report_id)
unsigned i;
if (report_id == 0) {
if (device->hidraw.reports[0].report_id == report_id)
return &device->hidraw.reports[0];
if (device->hidraw[0].reports[0].report_id == report_id)
return &device->hidraw[0].reports[0];
else
return NULL;
}
for (i = 0; i < device->hidraw.num_reports; i++) {
if (device->hidraw.reports[i].report_id == report_id)
return &device->hidraw.reports[i];
for (i = 0; i < device->hidraw[0].num_reports; i++) {
if (device->hidraw[0].reports[i].report_id == report_id)
return &device->hidraw[0].reports[i];
}
return NULL;
@@ -1507,20 +1517,28 @@ ratbag_hidraw_get_usage(struct ratbag_device *device, unsigned int report_id)
void
ratbag_close_hidraw(struct ratbag_device *device)
{
if (device->hidraw.fd < 0)
ratbag_close_hidraw_index(device, 0);
}
void
ratbag_close_hidraw_index(struct ratbag_device *device, int idx)
{
assert(idx >= 0 && idx < MAX_HIDRAW);
if (device->hidraw[idx].fd < 0)
return;
if (device->hidraw.sysname) {
free(device->hidraw.sysname);
device->hidraw.sysname = NULL;
if (device->hidraw[idx].sysname) {
free(device->hidraw[idx].sysname);
device->hidraw[idx].sysname = NULL;
}
ratbag_close_fd(device, device->hidraw.fd);
device->hidraw.fd = -1;
ratbag_close_fd(device, device->hidraw[idx].fd);
device->hidraw[idx].fd = -1;
if (device->hidraw.reports) {
free(device->hidraw.reports);
device->hidraw.reports = NULL;
if (device->hidraw[idx].reports) {
free(device->hidraw[idx].reports);
device->hidraw[idx].reports = NULL;
}
}
@@ -1531,7 +1549,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum,
uint8_t tmp_buf[HID_MAX_BUFFER_SIZE];
int rc;
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw.fd < 0)
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0)
return -EINVAL;
if (rtype != HID_FEATURE_REPORT)
@@ -1542,7 +1560,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum,
memset(tmp_buf, 0, len);
tmp_buf[0] = reportnum;
rc = ioctl(device->hidraw.fd, HIDIOCGFEATURE(len), tmp_buf);
rc = ioctl(device->hidraw[0].fd, HIDIOCGFEATURE(len), tmp_buf);
if (rc < 0)
return -errno;
@@ -1554,7 +1572,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum,
buf[0] = reportnum;
log_buf_raw(device->ratbag, "feature set: ", buf, len);
rc = ioctl(device->hidraw.fd, HIDIOCSFEATURE(len), buf);
rc = ioctl(device->hidraw[0].fd, HIDIOCSFEATURE(len), buf);
if (rc < 0)
return -errno;
@@ -1569,12 +1587,12 @@ ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t l
{
int rc;
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw.fd < 0)
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0)
return -EINVAL;
log_buf_raw(device->ratbag, "output report: ", buf, len);
rc = write(device->hidraw.fd, buf, len);
rc = write(device->hidraw[0].fd, buf, len);
if (rc < 0)
return -errno;
@@ -1587,14 +1605,22 @@ ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t l
int
ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len)
{
return ratbag_hidraw_read_input_report_index(device, buf, len, 0);
}
int
ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno)
{
int rc;
struct pollfd fds;
if (len < 1 || !buf || device->hidraw.fd < 0)
assert(hidrawno >= 0 && hidrawno < MAX_HIDRAW);
if (len < 1 || !buf || device->hidraw[hidrawno].fd < 0)
return -EINVAL;
fds.fd = device->hidraw.fd;
fds.fd = device->hidraw[hidrawno].fd;
fds.events = POLLIN;
rc = poll(&fds, 1, 1000);
@@ -1604,7 +1630,7 @@ ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size
if (rc == 0)
return -ETIMEDOUT;
rc = read(device->hidraw.fd, buf, len);
rc = read(device->hidraw[hidrawno].fd, buf, len);
if (rc > 0)
log_buf_raw(device->ratbag, "input report: ", buf, rc);

View File

@@ -32,6 +32,7 @@
#define HID_INPUT_REPORT 0
#define HID_OUTPUT_REPORT 1
#define HID_FEATURE_REPORT 2
#define MAX_HIDRAW 2
struct ratbag_hid_report {
unsigned int report_id;
@@ -55,6 +56,18 @@ struct ratbag_hidraw {
*/
int ratbag_open_hidraw(struct ratbag_device *device);
/**
* Open a hidraw device associated with the device by its enumeration order to
* a specific internal hidraw index.
*
* @param device the ratbag device
* @param enumeration index of the endpoint
* @param interal index of hidraw array
*
* @return 0 on success or a negative errno on error
*/
int ratbag_open_hidraw_index(struct ratbag_device *device, int endpoint_index, int hidraw_index);
/**
* Find and open the hidraw device associated with the device by using the
* given matching function.
@@ -75,6 +88,14 @@ ratbag_find_hidraw(struct ratbag_device *device,
*/
void ratbag_close_hidraw(struct ratbag_device *device);
/**
* Close a hidraw device associated with the device by the internal index.
*
* @param device the ratbag device
* @param interal index of hidraw array
*/
void ratbag_close_hidraw_index(struct ratbag_device *device, int idx);
/**
* Send report request to device
*
@@ -115,6 +136,19 @@ int ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size
*/
int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len);
/**
* Read an input report from the device from a specific hidraw index
*
* @param device the ratbag device
* @param[out] buf resulting raw data
* @param len length of buf
* @param interal index of hidraw array
*
* @return count of data transfered, or a negative errno on error
*/
int ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno);
/**
* Tells if a given device has the specified report ID.
*

View File

@@ -129,7 +129,7 @@ struct ratbag_device {
void *userdata;
struct udev_device *udev_device;
struct ratbag_hidraw hidraw;
struct ratbag_hidraw hidraw[MAX_HIDRAW];
int refcount;
struct input_id ids;
struct ratbag_driver *driver;
@@ -262,7 +262,7 @@ struct ratbag_resolution {
unsigned int dpi_y; /**< y resolution in dpi */
unsigned int hz; /**< report rate in Hz */
unsigned int rates[5];
unsigned int rates[8];
size_t nrates;
bool is_active;
@@ -603,6 +603,7 @@ struct ratbag_driver etekcity_driver;
struct ratbag_driver hidpp20_driver;
struct ratbag_driver hidpp10_driver;
struct ratbag_driver logitech_g300_driver;
struct ratbag_driver logitech_g600_driver;
struct ratbag_driver roccat_driver;
struct ratbag_driver gskill_driver;
struct ratbag_driver steelseries_driver;

View File

@@ -583,6 +583,7 @@ ratbag_create_context(const struct ratbag_interface *interface,
ratbag_register_driver(ratbag, &hidpp20_driver);
ratbag_register_driver(ratbag, &hidpp10_driver);
ratbag_register_driver(ratbag, &logitech_g300_driver);
ratbag_register_driver(ratbag, &logitech_g600_driver);
ratbag_register_driver(ratbag, &roccat_driver);
ratbag_register_driver(ratbag, &gskill_driver);
ratbag_register_driver(ratbag, &steelseries_driver);
@@ -649,7 +650,7 @@ ratbag_create_led(struct ratbag_profile *profile, unsigned int index)
return led;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_profile_has_capability(const struct ratbag_profile *profile,
enum ratbag_profile_capability cap)
{
@@ -831,16 +832,16 @@ ratbag_profile_set_enabled(struct ratbag_profile *profile, bool enabled)
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_profile_is_active(struct ratbag_profile *profile)
{
return profile->is_active;
return !!profile->is_active;
}
LIBRATBAG_EXPORT bool
ratbag_profile_is_enabled(const struct ratbag_profile *profile)
{
return profile->is_enabled;
return !!profile->is_enabled;
}
LIBRATBAG_EXPORT unsigned int
@@ -892,7 +893,7 @@ ratbag_device_unset_capability(struct ratbag_device *device,
long_clear_bit(device->capabilities, cap);
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_device_has_capability(const struct ratbag_device *device,
enum ratbag_device_capability cap)
{
@@ -1001,7 +1002,7 @@ ratbag_device_commit(struct ratbag_device *device)
list_for_each(resolution, &profile->resolutions, link)
resolution->dirty = false;
}
return RATBAG_SUCCESS;
@@ -1083,7 +1084,7 @@ ratbag_resolution_unref(struct ratbag_resolution *resolution)
return NULL;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_resolution_has_capability(struct ratbag_resolution *resolution,
enum ratbag_resolution_capability cap)
{
@@ -1226,10 +1227,10 @@ ratbag_resolution_get_report_rate_list(struct ratbag_resolution *resolution,
return resolution->nrates;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_resolution_is_active(const struct ratbag_resolution *resolution)
{
return resolution->is_active;
return !!resolution->is_active;
}
LIBRATBAG_EXPORT enum ratbag_error_code
@@ -1248,10 +1249,10 @@ ratbag_resolution_set_active(struct ratbag_resolution *resolution)
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_resolution_is_default(const struct ratbag_resolution *resolution)
{
return resolution->is_default;
return !!resolution->is_default;
}
LIBRATBAG_EXPORT enum ratbag_error_code
@@ -1314,7 +1315,7 @@ ratbag_button_get_action_type(struct ratbag_button *button)
return button->action.type;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_button_has_action_type(struct ratbag_button *button,
enum ratbag_button_action_type action_type)
{
@@ -1544,7 +1545,7 @@ ratbag_led_get_type(struct ratbag_led *led)
return led->type;
}
LIBRATBAG_EXPORT int
LIBRATBAG_EXPORT bool
ratbag_led_has_mode(struct ratbag_led *led,
enum ratbag_led_mode mode)
{
@@ -1553,7 +1554,7 @@ ratbag_led_has_mode(struct ratbag_led *led,
if (mode == RATBAG_LED_OFF)
return 1;
return (led->modes & (1 << mode));
return !!(led->modes & (1 << mode));
}
LIBRATBAG_EXPORT struct ratbag_color
@@ -1681,6 +1682,7 @@ ratbag_profile_set_name(struct ratbag_profile *profile,
free(profile->name);
profile->name = name_copy;
profile->dirty = true;
return 0;
}

View File

@@ -452,7 +452,7 @@ ratbag_device_get_svg_name(const struct ratbag_device* device);
* @retval 1 The device has the capability
* @retval 0 The device does not have the capability
*/
int
bool
ratbag_device_has_capability(const struct ratbag_device *device,
enum ratbag_device_capability cap);
@@ -540,7 +540,7 @@ ratbag_profile_unref(struct ratbag_profile *profile);
*
* @return non-zero if the capability is available, zero otherwise.
*/
int
bool
ratbag_profile_has_capability(const struct ratbag_profile *profile,
enum ratbag_profile_capability cap);
@@ -655,7 +655,7 @@ ratbag_device_get_profile(struct ratbag_device *device, unsigned int index);
*
* @return non-zero if the profile is currently active, zero otherwise
*/
int
bool
ratbag_profile_is_active(struct ratbag_profile *profile);
/**
@@ -771,7 +771,7 @@ ratbag_resolution_get_user_data(const struct ratbag_resolution *resolution);
*
* @return non-zero if the capability is available, zero otherwise.
*/
int
bool
ratbag_resolution_has_capability(struct ratbag_resolution *resolution,
enum ratbag_resolution_capability cap);
@@ -988,7 +988,7 @@ ratbag_resolution_set_active(struct ratbag_resolution *resolution);
* @return Non-zero if the resolution mode is the active one, zero
* otherwise.
*/
int
bool
ratbag_resolution_is_active(const struct ratbag_resolution *resolution);
/**
@@ -1023,7 +1023,7 @@ ratbag_resolution_set_default(struct ratbag_resolution *resolution);
* @return Non-zero if the resolution mode is the default one, zero
* otherwise.
*/
int
bool
ratbag_resolution_is_default(const struct ratbag_resolution *resolution);
/**
@@ -1117,7 +1117,7 @@ ratbag_button_get_action_type(struct ratbag_button *button);
*
* @return non-zero if the action type is supported, zero otherwise.
*/
int
bool
ratbag_button_has_action_type(struct ratbag_button *button,
enum ratbag_button_action_type action_type);
@@ -1218,7 +1218,7 @@ ratbag_led_get_type(struct ratbag_led *led);
*
* @see ratbag_led_set_mode
*/
int
bool
ratbag_led_has_mode(struct ratbag_led *led,
enum ratbag_led_mode mode);

View File

@@ -135,6 +135,7 @@ static inline void reset_errno(int *saved_errno)
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref);
/*
* ELEMENTSOF() - number of array elements

99
tools/check_scan_build.py Executable file
View File

@@ -0,0 +1,99 @@
#!/bin/env python3
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
import bs4
import os
import re
import sys
class Bug(object):
def __init__(self):
self.line_number = None
self.cfile = None
self.sa_type = None
self.sa_descr = None
def main(argv):
if len(argv) < 2:
print(f'usage {argv[0]} PATH')
sys.exit(1)
scanbuild_path = argv[1]
ignored = []
bugs = []
line_re = re.compile(r'line (\d+), column (\d+)')
for root, dirs, files in os.walk(scanbuild_path):
for filename in files:
if not filename.startswith('report'):
continue
with open(os.path.join(root, filename)) as f:
soup = bs4.BeautifulSoup(f, 'html.parser')
# the first table is the summary
summary = soup.table
bug = Bug()
# iterate over the table
for tr in summary('tr'):
if 'File:' in tr.contents[0].string:
bug.cfile = os.path.abspath(tr.contents[1].string)
else:
bug.sa_type = tr.contents[0].string.rstrip(':').lower()
for s in tr.contents[1].strings:
# retrieve the line number and the description
m = line_re.match(s)
if m is None:
bug.sa_descr = s
else:
bug.line_number = int(m.group(1))
# retrieve the html line corresponding to the code
code = soup.find('td', id=f'LN{bug.line_number}').parent
# fetching any comments in this line
try:
comments = code.find('span', class_='comment').string
except AttributeError:
# no comments on the line
bugs.append(bug)
else:
if 'ignore_clang_sa_' in comments:
ignored.append(bug)
else:
bugs.append(bug)
if len(ignored) > 0:
print(f'{len(ignored)} bugs are ignored:')
for b in ignored:
print(f' {b.sa_type}: {b.sa_descr} at {b.cfile}:{b.line_number}')
if len(bugs) > 0:
print()
if len(bugs) > 0:
print(f'ERROR: {len(bugs)} bugs found:')
for b in bugs:
print(f' * {b.sa_type.upper()}: {b.sa_descr} at {b.cfile}:{b.line_number}')
sys.exit(1)
sys.exit(0)
if __name__ == '__main__':
main(sys.argv)

View File

@@ -31,6 +31,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <liblur.h>
#include <libratbag-util.h>

View File

@@ -30,7 +30,7 @@ import sys
def print_ratbagctl(ratbagctl_path, ratbagd_path, version_string):
with open(ratbagctl_path, 'r') as ratbagctl, open(ratbagd_path, 'r') as ratbagd:
with open(ratbagctl_path, 'r', encoding='utf-8') as ratbagctl, open(ratbagd_path, 'r', encoding='utf-8') as ratbagd:
for l in ratbagctl.readlines():
if l.startswith("from ratbagd import "):
headers = True
@@ -53,7 +53,7 @@ def main(argv):
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')
ns.output_file = open(ns.output, 'w', encoding='utf-8')
st = os.stat(ns.output)
os.chmod(ns.output, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
sys.stdout = ns.output_file

View File

@@ -26,6 +26,7 @@
import evdev
import sys
import argparse
import re
from ratbagd import Ratbagd, RatbagdDevice, RatbagdProfile, RatbagdMacro, RatbagdResolution, RatbagdButton, RatbagdLed, RatbagdDBusUnavailable, RatbagError, RatbagErrorCode, RatbagErrorCapability # NOQA
@@ -266,8 +267,18 @@ def print_device(d, level):
RatbagdDevice.CAP_LED: "led"}
capabilities = [caps[c] for c in d.capabilities]
svg_name = 'unknown'
try:
with d.get_svg_fd('gnome') as fd:
svg = fd.read()
match = re.search('sodipodi:docname=".*"\n', svg)
if match:
svg_name = match.group(0).split('"')[1]
except FileNotFoundError:
pass
print(" " * level + "{} - {}".format(d.id, d.name))
print(" " * level + " SVG: {}".format(d.get_svg('gnome')))
print(" " * level + " SVG: {}".format(svg_name))
print(" " * level + " Capabilities: {}".format(", ".join(capabilities)))
print(" " * level + " Number of Buttons: {}".format(len(p.buttons)))
print(" " * level + " Number of Leds: {}".format(len(p.leds)))

View File

@@ -232,6 +232,35 @@ class _RatbagdDBus(GObject.GObject):
print(e.message, file=sys.stderr)
raise
def _dbus_call_return_one_fd(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_with_unix_fd_list_sync(method, val,
Gio.DBusCallFlags.NO_AUTO_START,
2000, None, None)
if res in EXCEPTION_TABLE:
raise EXCEPTION_TABLE[res]
# Result is a tuple of (GLib.Variant('(h)', (0,)), fd_list),
# we return the first file descriptor in that list
return res[1].get(0)
except GLib.Error as e:
if e.code == Gio.DBusError.FILE_NOT_FOUND:
raise FileNotFoundError('Failed to open SVG file')
elif 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
@@ -253,7 +282,7 @@ class Ratbagd(_RatbagdDBus):
def __init__(self):
_RatbagdDBus.__init__(self, "Manager", None)
result = self._get_dbus_property("Devices")
result = self._get_dbus_property("Devices") or []
self._devices = [RatbagdDevice(objpath) for objpath in result]
def _on_properties_changed(self, proxy, changed_props, invalidated_props):
@@ -286,7 +315,7 @@ class Ratbagd(_RatbagdDBus):
def themes(self):
"""A list of theme names. The theme 'default' is guaranteed to be
available."""
return self._get_dbus_property("Themes")
return self._get_dbus_property("Themes") or []
def __enter__(self):
return self
@@ -321,7 +350,7 @@ class RatbagdDevice(_RatbagdDBus):
# FIXME: if we start adding and removing objects from this list,
# things will break!
result = self._get_dbus_property("Profiles")
result = self._get_dbus_property("Profiles") or []
self._profiles = [RatbagdProfile(objpath) for objpath in result]
for profile in self._profiles:
profile.connect("notify::is-active", self._on_active_profile_changed)
@@ -343,7 +372,7 @@ class RatbagdDevice(_RatbagdDBus):
if RatbagdDevice.CAP_SWITCHABLE_RESOLUTION is in device.capabilities:
do something
"""
return self._get_dbus_property("Capabilities")
return self._get_dbus_property("Capabilities") or []
@GObject.Property
def name(self):
@@ -367,6 +396,19 @@ class RatbagdDevice(_RatbagdDBus):
print("No active profile. Please report this bug to the libratbag developers", file=sys.stderr)
return self._profiles[0]
def get_svg_fd(self, theme):
"""Returns a File-like object to the SVG for the given theme, or
raises FileNotFoundError if the file is not available.
The theme must be one of org.freedesktop.ratbag1.Manager.Themes. The
theme 'default' is guaranteed to be available (but the file itself
may not be).
@param theme The theme from which to retrieve the SVG, as str
"""
fd = self._dbus_call_return_one_fd("GetSvgFd", "s", theme)
return os.fdopen(fd)
def get_svg(self, theme):
"""Gets the full path to the SVG for the given theme, or the empty
string if none is available.
@@ -411,15 +453,15 @@ class RatbagdProfile(_RatbagdDBus):
# FIXME: if we start adding and removing objects from any of these
# lists, things will break!
result = self._get_dbus_property("Resolutions")
result = self._get_dbus_property("Resolutions") or []
self._resolutions = [RatbagdResolution(objpath) for objpath in result]
self._subscribe_dirty(self._resolutions)
result = self._get_dbus_property("Buttons")
result = self._get_dbus_property("Buttons") or []
self._buttons = [RatbagdButton(objpath) for objpath in result]
self._subscribe_dirty(self._buttons)
result = self._get_dbus_property("Leds")
result = self._get_dbus_property("Leds") or []
self._leds = [RatbagdLed(objpath) for objpath in result]
self._subscribe_dirty(self._leds)
@@ -448,7 +490,7 @@ class RatbagdProfile(_RatbagdDBus):
if RatbagdProfile.CAP_WRITABLE_NAME is in profile.capabilities:
do something
"""
return self._get_dbus_property("Capabilities")
return self._get_dbus_property("Capabilities") or []
@GObject.Property
def name(self):
@@ -565,7 +607,7 @@ class RatbagdResolution(_RatbagdDBus):
if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION is in resolution.capabilities:
do something
"""
return self._get_dbus_property("Capabilities")
return self._get_dbus_property("Capabilities") or []
@GObject.Property
def resolution(self):
@@ -596,12 +638,12 @@ class RatbagdResolution(_RatbagdDBus):
@GObject.Property
def resolutions(self):
"""The list of supported DPI values"""
return self._get_dbus_property("Resolutions")
return self._get_dbus_property("Resolutions") or []
@GObject.Property
def report_rates(self):
"""The list of supported report rates"""
return self._get_dbus_property("ReportRates")
return self._get_dbus_property("ReportRates") or []
@GObject.Property
def is_active(self):

View File

@@ -61,6 +61,8 @@ def start_ratbagd(verbosity=0):
from gi.repository import Gio
import time
os.makedirs(DBUS_CONF_DIR, exist_ok=True)
# 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_PATH)
@@ -73,6 +75,8 @@ def start_ratbagd(verbosity=0):
args.append('--verbose=raw')
elif verbosity >= 2:
args.append('--verbose')
elif verbosity == 0:
args.append('--quiet')
ratbagd_process = subprocess.Popen(args, shell=False, stdout=sys.stdout, stderr=sys.stderr)