mirror of
https://github.com/clearlinux/linux-steam-integration.git
synced 2026-09-06 22:01:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53fec0a8b6 | ||
|
|
41c117918c | ||
|
|
88792a27ea | ||
|
|
24c26aeab7 | ||
|
|
ed0153c825 | ||
|
|
7d5ff6a5d4 | ||
|
|
b1852cb803 | ||
|
|
c524679428 | ||
|
|
2388f6f693 | ||
|
|
8cdb63fd7e | ||
|
|
8591b35a8e | ||
|
|
950897ab0d | ||
|
|
45b5652109 | ||
|
|
329f8de9aa | ||
|
|
b001cbf750 | ||
|
|
ec78c17316 | ||
|
|
20db0cad18 | ||
|
|
446152e8ad | ||
|
|
65805e2d0a | ||
|
|
32326af2b3 | ||
|
|
8c304bcd16 | ||
|
|
893100c174 | ||
|
|
709f5cd1c2 | ||
|
|
8f531f3be8 | ||
|
|
e1e4c11b8d | ||
|
|
347b41f990 | ||
|
|
e7b2d6f70e | ||
|
|
5732bc2fca | ||
|
|
514a7fabb1 | ||
|
|
44a195274b | ||
|
|
212d938e25 | ||
|
|
db4c33fce1 | ||
|
|
3355bb7cff | ||
|
|
3b40061748 | ||
|
|
1edead3929 | ||
|
|
da439aa484 | ||
|
|
991e12d6cd | ||
|
|
87bf493350 | ||
|
|
22c9805c16 | ||
|
|
84a4dd59a9 | ||
|
|
8684a992b0 | ||
|
|
4303b14f45 | ||
|
|
7456c9c26a | ||
|
|
0a84ba7fc4 | ||
|
|
981fe43071 | ||
|
|
63aba59c27 | ||
|
|
3485ab87eb | ||
|
|
e2325befba | ||
|
|
a89de2bb58 | ||
|
|
ede4e130f4 | ||
|
|
d4eb0ca042 | ||
|
|
bfb703be68 | ||
|
|
d0708a2332 | ||
|
|
a7c59cacef | ||
|
|
799c4b1e48 | ||
|
|
ada9b92f53 | ||
|
|
60c3ddc6e9 | ||
|
|
c3a071e2a0 | ||
|
|
4001ffc814 | ||
|
|
e3a4640c04 | ||
|
|
bddeda6ef3 | ||
|
|
71322156e3 | ||
|
|
c5bb4ca040 | ||
|
|
a2502c1ec7 | ||
|
|
2b2e73b572 | ||
|
|
a98ebc3607 | ||
|
|
78fcdf6247 | ||
|
|
516823ae3c | ||
|
|
f2352546d4 | ||
|
|
b87210a253 | ||
|
|
2d6ab6d497 | ||
|
|
ffdc14c109 | ||
|
|
e45340973a | ||
|
|
1f73dd3e0b | ||
|
|
fb50dca553 | ||
|
|
edf3176c70 | ||
|
|
e73d384726 | ||
|
|
30152b9604 | ||
|
|
a83b1c24b2 | ||
|
|
0f33bb1fbd | ||
|
|
88550aeffc | ||
|
|
fe83d34984 | ||
|
|
9b4187ed27 | ||
|
|
b40eba8ad9 | ||
|
|
1179763531 | ||
|
|
627c7639cf | ||
|
|
290260c09e | ||
|
|
a691985541 | ||
|
|
1811ff5225 | ||
|
|
a932486826 | ||
|
|
3c69b6dc05 | ||
|
|
c8f0cecb15 | ||
|
|
3b01919148 | ||
|
|
474aca0b69 | ||
|
|
fa81893d41 | ||
|
|
f958b8ac3f | ||
|
|
971d0c280e | ||
|
|
4f6166bdce | ||
|
|
be98e146ed | ||
|
|
5c131f6b28 | ||
|
|
8768730414 | ||
|
|
68fe3c1c11 | ||
|
|
dc85a14bfb | ||
|
|
c646ee516e | ||
|
|
bb29a04078 | ||
|
|
0eb0d09119 | ||
|
|
5810e63576 | ||
|
|
01faa3754d | ||
|
|
b4e512b708 | ||
|
|
95613a45f8 | ||
|
|
312b7a888a | ||
|
|
071304d8bd | ||
|
|
36e6cf5455 | ||
|
|
26dc2503d2 | ||
|
|
1d81c2094f | ||
|
|
fe063b1624 | ||
|
|
fa41b2c572 | ||
|
|
feae99a359 | ||
|
|
34fe25a533 | ||
|
|
6349652740 | ||
|
|
665caee634 | ||
|
|
be3023263f | ||
|
|
27e5cd0ae0 | ||
|
|
79fece840c | ||
|
|
478a0f1810 | ||
|
|
2cf5db42b3 | ||
|
|
191ea02946 | ||
|
|
03dd537574 | ||
|
|
8ded405801 | ||
|
|
35b3f132fd | ||
|
|
4b718a4bc7 | ||
|
|
5ceacb27fb | ||
|
|
d1b7a86867 | ||
|
|
0c252321e3 | ||
|
|
b9d677dee1 | ||
|
|
86fbf11040 | ||
|
|
ec67c801ad | ||
|
|
0a02c111a0 | ||
|
|
48a9bac406 | ||
|
|
8de8962099 | ||
|
|
de9380dc8d | ||
|
|
9bd423fb34 | ||
|
|
75d2e9cc45 | ||
|
|
7d0acc9891 | ||
|
|
7bae532d85 | ||
|
|
4f332c9acf | ||
|
|
f2dddd9f88 | ||
|
|
94d5c6d939 | ||
|
|
f4564e2ab8 | ||
|
|
8d85cb3bed | ||
|
|
fb2e84cb97 | ||
|
|
e1f2783d11 | ||
|
|
13afbe69c3 | ||
|
|
b458346f5a | ||
|
|
bf4fcfe533 | ||
|
|
b7ba890433 | ||
|
|
faa0c3a154 | ||
|
|
99e54dd74b | ||
|
|
5d18366a17 | ||
|
|
6154f2373c | ||
|
|
fe80861f66 | ||
|
|
38ec05ce98 | ||
|
|
d983f8ebdf | ||
|
|
4d3abc5e37 | ||
|
|
47e50b789f | ||
|
|
9905a2bc81 | ||
|
|
11e1d8ae5f | ||
|
|
00e78f705e | ||
|
|
54c685bb1a | ||
|
|
a61e22d677 | ||
|
|
93b0f82279 | ||
|
|
d870577a55 | ||
|
|
fd252e265d | ||
|
|
3684dfe11e | ||
|
|
d5b31dbf54 | ||
|
|
f6dcc30d33 | ||
|
|
7a2670f3e1 | ||
|
|
61d9296a6c | ||
|
|
f2bbe963b6 | ||
|
|
4547d8582a | ||
|
|
1db376fa38 | ||
|
|
0bf704fc79 | ||
|
|
cf023ffb6a | ||
|
|
4b36347ade | ||
|
|
d3469e3eb0 | ||
|
|
29081c492d | ||
|
|
ac76372b84 | ||
|
|
6b107f33b5 | ||
|
|
ba8ae8f384 | ||
|
|
d77ad58934 | ||
|
|
2aae934271 | ||
|
|
12d5268252 | ||
|
|
15253b97df | ||
|
|
8dd27f6f24 | ||
|
|
f21559ee78 | ||
|
|
5b17fe9447 | ||
|
|
9ca7ffdd85 | ||
|
|
3b552ec17d | ||
|
|
a3226a293c | ||
|
|
9c40a9d106 | ||
|
|
49d68c52a7 | ||
|
|
d20c230067 | ||
|
|
bd4707f3ca | ||
|
|
1a70578cb1 | ||
|
|
7995688ea2 | ||
|
|
e3360b7ddc | ||
|
|
1700f2616c | ||
|
|
6f8e905569 | ||
|
|
7c0ff5031e | ||
|
|
dd5237e648 | ||
|
|
2282296045 | ||
|
|
ba48264207 | ||
|
|
bddc0f29b1 | ||
|
|
196a039746 | ||
|
|
4ff98e225a | ||
|
|
e49a7873fe | ||
|
|
6659905102 | ||
|
|
16702d0d8f | ||
|
|
00d8831720 | ||
|
|
451ffe7680 |
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
+2
-18
@@ -1,18 +1,2 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
build-aux/
|
||||
config.*
|
||||
configure
|
||||
libtool
|
||||
stamp-h1
|
||||
m4/*.m4
|
||||
.deps
|
||||
.dirstamp
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
/steam
|
||||
/lsi-settings
|
||||
/buildroot/
|
||||
/build/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "src/libnica"]
|
||||
path = src/libnica
|
||||
url = https://github.com/intel/libnica.git
|
||||
@@ -0,0 +1,8 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[linux-steam-integration.linux-steam-integrationpot]
|
||||
file_filter = po/<lang>.po
|
||||
source_lang = en
|
||||
type = PO
|
||||
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
EXTRA_DIST = \
|
||||
LICENSE.LGPL2.1 \
|
||||
README.rst \
|
||||
data/lsi-settings.desktop
|
||||
|
||||
AM_CFLAGS = \
|
||||
-fstack-protector -Wall -pedantic \
|
||||
-Wstrict-prototypes -Wundef -fno-common \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wformat -Wformat-security -Werror=format-security \
|
||||
-Wno-conversion -Wunused-variable -Wunreachable-code \
|
||||
-Wall -W -D_FORTIFY_SOURCE=2 -std=c99
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I $(top_srcdir)/src \
|
||||
-I $(top_srcdir)/src/shim \
|
||||
-I $(top_srcdir)/src/nica \
|
||||
-DSYSTEMCONFDIR=\"$(sysconfdir)\" \
|
||||
-DVENDORDIR=\"$(datadir)/defaults/linux-steam-integration\"
|
||||
|
||||
|
||||
noinst_LTLIBRARIES = \
|
||||
libnica.la \
|
||||
liblsi.la
|
||||
|
||||
bin_PROGRAMS = \
|
||||
steam
|
||||
|
||||
if HAVE_FRONTEND
|
||||
bin_PROGRAMS += lsi-settings
|
||||
|
||||
lsi_settings_SOURCES = \
|
||||
src/frontend/main.c
|
||||
|
||||
lsi_settings_CFLAGS = \
|
||||
$(GTK_CFLAGS) \
|
||||
$(AM_CFLAGS) \
|
||||
-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_3_4 \
|
||||
-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_4
|
||||
|
||||
lsi_settings_LDADD = \
|
||||
liblsi.la \
|
||||
$(GTK_LIBS)
|
||||
|
||||
desktopdir = $(datadir)/applications
|
||||
desktop_DATA = \
|
||||
data/lsi-settings.desktop
|
||||
|
||||
endif
|
||||
|
||||
# Convenience library to prevent external linking with currently unstable ABI
|
||||
libnica_la_SOURCES = \
|
||||
src/nica/hashmap.h \
|
||||
src/nica/hashmap.c \
|
||||
src/nica/inifile.h \
|
||||
src/nica/inifile.c \
|
||||
src/nica/util.h
|
||||
|
||||
libnica_la_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
|
||||
# Convenience library for shared LSI functions
|
||||
liblsi_la_SOURCES = \
|
||||
src/shim/lsi.h \
|
||||
src/shim/lsi.c
|
||||
|
||||
liblsi_la_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
liblsi_la_LIBADD = \
|
||||
libnica.la
|
||||
|
||||
steam_SOURCES = \
|
||||
src/shim/shim.c
|
||||
|
||||
steam_LDADD = \
|
||||
libnica.la \
|
||||
liblsi.la
|
||||
|
||||
steam_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
@@ -0,0 +1,63 @@
|
||||
linux-steam-integration
|
||||
-----------------------
|
||||
|
||||
Linux Steam* Integration is a helper system to make the Steam Client and Steam
|
||||
games run better on Linux. In a nutshell, LSI automatically applies various workarounds
|
||||
to get games working, and fixes long standing bugs in both games and the client.
|
||||
|
||||

|
||||
|
||||
In many cases this will involve controlling which libraries are allowed to be used
|
||||
at any given time, and these libraries may be overriden for any of the following
|
||||
reasons:
|
||||
|
||||
- Security
|
||||
- Compatibility
|
||||
- Performance
|
||||
|
||||
Additionally we apply dynamic workarounds to fix some filesystem path related bugs in Linux
|
||||
ports (or even shader workarounds for ARK*) through our redirect module.
|
||||
|
||||
With LSI, you don't need to worry any more about manually mangling your Steam installation
|
||||
just to make the open source drivers work, or manually creating links and installing
|
||||
unsupported libraries. LSI is designed to take care of all of this for you.
|
||||
|
||||
Note that LSI will not modify your Steam installation, and instead makes use of two
|
||||
modules, `liblsi-redirect.so` and `liblsi-intercept.so`, to dynamically apply all of the
|
||||
workarounds at runtime, which in turn is set up by the main LSI `shim` binary.
|
||||
|
||||
For a more in depth view of what LSI is, and how to integrate it into your distribution,
|
||||
please check the [technical README document](https://github.com/solus-project/linux-steam-integration/blob/master/TECHNICAL.md).
|
||||
|
||||
Do note that we intend to remove the need for distributions to integrate LSI in the near future, by providing
|
||||
the LSI system as a [snap](https://snapcraft.io/) package for all supported distributions.
|
||||
|
||||
This project, and by extension Solus, is not officially endorsed by, or affiliated with, Steam, or its parent company, Valve*.
|
||||
|
||||
Linux Steam Integration is a [Solus project](https://solus-project.com/)
|
||||
|
||||

|
||||
|
||||
## Getting LSI
|
||||
|
||||
LSI may not yet be available for your distribution, however some community maintained repositories do exist.
|
||||
|
||||
- [Arch Linux](https://aur.archlinux.org/packages/linux-steam-integration/)
|
||||
- [Fedora](https://copr.fedorainfracloud.org/coprs/alunux/linux-steam-integration/)
|
||||
- Solus uses LSI by default, just install the `steam` package.
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2016-2017 Ikey Doherty
|
||||
|
||||
linux-steam-integration is available under the terms of the `LGPL-2.1` license.
|
||||
|
||||
See the accompanying `LICENSE.LGPL2.1` file for more details
|
||||
|
||||
|
||||
`data/lsi-steam.desktop`:
|
||||
|
||||
This file borrows translations from the official `steam.desktop` launcher.
|
||||
These are copyright of Valve*.
|
||||
|
||||
`* Some names may be claimed as the property of others.`
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
linux-steam-integration
|
||||
-----------------------
|
||||
|
||||
A helper shim to enable better Steam* integration on Linux systems.
|
||||
This is part of an effort by Solus to enhance Steam for everyone.
|
||||
|
||||
This project, and by extension Solus, is not officially endorsed by, or
|
||||
affiliated with, Steam*, or its parent company, Valve*.
|
||||
|
||||
|
||||
Linux Steam Integration (LSI) is a `Solus Project <https://github.com/solus-project/linux-steam-integration/issues/2>`_
|
||||
|
||||
.. image:: https://build.solus-project.com/logo.png
|
||||
:align: center
|
||||
:alt: LSI is a Solus Project
|
||||
|
||||
|
||||
Integrating LSI
|
||||
===============
|
||||
|
||||
To correctly integrate LSI, your Steam package will require modification.
|
||||
LSI must provide the /usr/bin/steam binary, so your Steam package must
|
||||
move the main launcher to a shadow location.
|
||||
|
||||
**Configuring LSI build**
|
||||
|
||||
There are a number of configure options you should be aware of when integrating
|
||||
LSI correctly. The prominent ones are explained here.
|
||||
|
||||
|
||||
|
||||
``--with-real-steam-binary=$NAME``
|
||||
|
||||
Set the absolute path for the shadowed Steam binary.
|
||||
LSI will execv Steam after it has initialised the environment.
|
||||
Note that execv, not execvp, is used, to mask programs that may be
|
||||
in the ``$PATH``, hence requiring an absolute path.
|
||||
|
||||
The default value for this option is::
|
||||
|
||||
/usr/lib/steam/steam
|
||||
|
||||
``--with-preload-libs=$LIBS``
|
||||
|
||||
A colon separated list of libraries that are required to launch Steam
|
||||
when using its own runtime. LSI enables users to switch back to the Steam
|
||||
runtime, and in this instance we manage the LD_PRELOAD environmental variable.
|
||||
Ensure this is correct, and escape $LIB for correct Linux usage.
|
||||
|
||||
The default value for this option is::
|
||||
|
||||
/usr/\$LIB/libX11.so.6:/usr/\$LIB/libstdc++.so.6
|
||||
|
||||
``--enable-frontend``
|
||||
|
||||
A small UI application is shipped to enable configuration of LSI, which presents
|
||||
a simple GTK3 Dialog to the user. It is not enabled by default, it is up
|
||||
to the integrator to decide if they wish to employ lsi-settings, or implement
|
||||
an alternative.
|
||||
|
||||
The lsi-settings application will only ever write new configurations to the
|
||||
**user** settings file, and requires no special permissions.
|
||||
|
||||
The default value for this option is::
|
||||
|
||||
disabled
|
||||
|
||||
|
||||
**How LSI Works**
|
||||
|
||||
LSI provides a /usr/bin/steam binary to be used in place of the existing Steam script,
|
||||
which will then correctly set up the environment before swapping the process for the
|
||||
Steam process.
|
||||
|
||||
Configuration options can be placed in an INI-style configuration file in a series
|
||||
of locations, which are ordered by priority in a cascade::
|
||||
|
||||
~/.config/linux-steam-integration.conf
|
||||
/etc/linux-steam-integration.conf
|
||||
/usr/share/defaults/linux-steam-integration/linux-steam-integration.conf
|
||||
|
||||
The user configuration takes immediate priority. Secondly we have the system-wide
|
||||
configuration for affecting all accounts, and lastly the vendor configuration,
|
||||
which may be provided by the integrator.
|
||||
|
||||
Currently this INI file supports two options. The root section in this INI file
|
||||
must be ``[Steam]``.
|
||||
|
||||
``use-native-runtime = $boolean``
|
||||
|
||||
If set to a true boolean value, (yes/true/on), the host OS's native runtime
|
||||
will be used instead of the Steam provided runtime. If this is set to
|
||||
a false boolean value (no/false/off), then the startup will be modified
|
||||
to export the relevant ``LD_PRELOAD`` and ``STEAM_RUNTIME`` settings.
|
||||
|
||||
The default value of this variable is ``true``.
|
||||
|
||||
``force-32bit = $boolean``
|
||||
|
||||
If set to a true boolean value (yes/true/on), the shadowed Steam binary will
|
||||
be run via the ``linux32`` command. This will force the ``steam`` process
|
||||
and all children to believe they are running on a 32-bit system. This
|
||||
may be useful for 64-bit games that are buggy only on 64-bit.
|
||||
|
||||
If this is set to a false boolean value (no/false/off), then the
|
||||
shadowed Steam binary will be directly executed. Note that on 32-bit
|
||||
OSs this setting is ignored.
|
||||
|
||||
The default value of this variable is ``false``.
|
||||
|
||||
|
||||
Common issues
|
||||
=============
|
||||
|
||||
**Missing tray icon for Steam client using native OS runtime**
|
||||
|
||||
Ensure you have the 32-bit version of libappindicator installed. This
|
||||
is required for the tray icon. libappindicator falls back to a standard
|
||||
X11 tray icon in the absence of desktop appindicator support.
|
||||
|
||||
Related issue: `Steam tray icon missing #2 <https://github.com/solus-project/linux-steam-integration/issues/2>`_
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
``src/nica``::
|
||||
|
||||
Partial import of libnica, Copyright © Intel Corporation.
|
||||
|
||||
|
||||
Used within the shim component to ensure it is leak free
|
||||
and as lightweight as possible, due to needing to exec the
|
||||
main Steam* launcher.
|
||||
libnica is available under the terms of the `LGPL-2.1` license.
|
||||
|
||||
``src/shim src/frontend``::
|
||||
|
||||
Copyright © 2016 Ikey Doherty
|
||||
|
||||
|
||||
linux-steam-integration is available under the terms of the `LGPL-2.1`
|
||||
|
||||
|
||||
See `LICENSE.LGPL2.1 <LICENSE.LGPL2.1>`_ for more details
|
||||
|
||||
|
||||
* Some names may be claimed as the property of others.
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
linux-steam-integration
|
||||
-----------------------
|
||||
|
||||
Linux Steam Integration is a software package aimed squarely at Linux distribution developers.
|
||||
It is designed to offer a far better Steam* experience than the stock client, doing away with old
|
||||
integration issues and crashes.
|
||||
|
||||
### Native Libraries
|
||||
|
||||
LSI enforces the use of host-native libraries, both in the Steam Client (via `lsi-intercept`) and
|
||||
games themselves. This ensures Steam integrates properly, games run with the latest libraries
|
||||
and users get the best performance.
|
||||
|
||||
Currently the officially provided Steam runtime is based on very old Ubuntu 12.04 packages,
|
||||
and has some cherry-picked updates (SDL, for example). This causes lots of integration issues
|
||||
on most newer distributions, such as broken client behaviour with full screen videos, outright
|
||||
crashes on startup, mismatched C++ ABI, missing sound, ugly menus, broken font rendering,
|
||||
poor performance, etc.
|
||||
|
||||
In a nut shell, LSI will force most of Steam over to using native libraries. The intercept
|
||||
system is new as of 0.4, and will be extended in future to allow improving certain games
|
||||
on a process-name whitelisting basis.
|
||||
|
||||
### Configurable
|
||||
|
||||
You can easily toggle the use of the native runtime or the runtime provided with the official
|
||||
Steam package distribution. LSI doesn't butcher any files, so your local Steam directory does
|
||||
not need to be repaired or reinstalled. Just run `lsi-settings` and restart Steam.
|
||||
|
||||
Currently you can control whether the native runtime is used, force 32-bit mode for some troublesome
|
||||
ports, and control whether the intercept library is enabled (which will undo the various library
|
||||
mangling tricks of the Steam distribution to force the usage of the system libs via rtld-audit)
|
||||
|
||||
### Portable
|
||||
|
||||
You can (and should) stick this into any distro. Hit us up if you need help integrating, or need some
|
||||
portability changes made. We won't bite.
|
||||
|
||||
### Going beyond LSI
|
||||
|
||||
LSI solves a great many issues, however there is then still a responsibility for the integrating distribution
|
||||
to provide basic ABI compatibility, as well as being functionally comparable to the "stock" runtime.
|
||||
Our future plans will basically involve creating a project based around LSI and a specially produced,
|
||||
optimised Steam runtime, usable on all Linux distributions.
|
||||
|
||||
If you want to be part of that effort - and help bring a modern, optimised gaming experience to your Linux
|
||||
users, please get in contact. Let's do this once, and do it right.
|
||||
|
||||
|
||||
## Integrating LSI
|
||||
|
||||
To correctly integrate LSI, your Steam package will require modification. LSI must provide the `/usr/bin/steam binary`, so your Steam package must move the main launcher to a shadow location.
|
||||
|
||||
For users who do not have access to LSI in their distribution, because it has not been integrated yet, please configure with `-Dwith-shim=co-exist` to preserve your existing Steam integrity. Then use the "LSI Steam" shortcut in your menu to launch Steam via LSI.
|
||||
|
||||
**Configuring LSI build**
|
||||
|
||||
There are a number of meson configure options you should be aware of when integrating LSI correctly. The prominent ones are explained here.
|
||||
|
||||
`-Dwith-shim= none | co-exist | replacement`
|
||||
|
||||
Control behaviour of the shim build. `none` will disable building the main
|
||||
shim, required for actually launching Steam in the first place.
|
||||
|
||||
`co-exist` will ensure this does not conflict with the `/usr/bin/steam`
|
||||
path, providing a new `lsi-steam` binary and desktop file.
|
||||
|
||||
`replacement` will provide a drop-in replacement `/usr/bin/steam` binary
|
||||
shim responsible for bootstrapping Steam via LSI. This will require you
|
||||
to mask the original steam binary to a new location.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`replacement`
|
||||
|
||||
|
||||
`-Dwith-steam-binary=$PATH`
|
||||
|
||||
Set the absolute path for the shadowed Steam binary.
|
||||
LSI will execv Steam after it has initialised the environment.
|
||||
Note that execv, not execvp, is used, to mask programs that may be
|
||||
in the `$PATH`, hence requiring an absolute path.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`/usr/lib/steam/steam`
|
||||
|
||||
This option is only applicable for distribution integrators, when
|
||||
Steam replacement is enabled.
|
||||
|
||||
|
||||
`-Dwith-preload-libs=$LIBS`
|
||||
|
||||
A colon separated list of libraries that are required to launch Steam
|
||||
when using its own runtime. LSI enables users to switch back to the Steam
|
||||
runtime, and in this instance we manage the LD_PRELOAD environmental variable.
|
||||
Ensure this is correct, and escape $LIB for correct Linux usage.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`/usr/\$LIB/libX11.so.6:/usr/\$LIB/libstdc++.so.6`
|
||||
|
||||
`-Dwith-new-libcxx-abi=$boolean`
|
||||
|
||||
Enable this if your distribution uses a recent libstdc++ build, from
|
||||
GCC 6 or higher.
|
||||
|
||||
`-Dwith-frontend=$boolean`
|
||||
|
||||
A small UI application is shipped to enable configuration of LSI, which presents
|
||||
a simple GTK3 Dialog to the user. It is not enabled by default, it is up
|
||||
to the integrator to decide if they wish to employ lsi-settings, or implement
|
||||
an alternative.
|
||||
|
||||
The lsi-settings application will only ever write new configurations to the
|
||||
**user** settings file, and requires no special permissions.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`false`
|
||||
|
||||
`-Dwith-libressl-mode= none | native | shim`
|
||||
|
||||
Control how LSI's `liblsi-intercept.so` handles LibreSSL.
|
||||
|
||||
The intercept module can be configured to enhance security of Linux ports
|
||||
by ensuring they use up to date LibreSSL builds.
|
||||
|
||||
When set to `native`, it is assumed the distro is employing LibreSSL as the
|
||||
default libSSL ABI (i.e. `libssl.so.1.0.0`)
|
||||
|
||||
When set to `shim`, LSI will redirect name requests for the `libssl` and
|
||||
`libcrypto` libraries to a uniquely named LibreSSL build of libraries,
|
||||
allowing libressl + openssl to co-exist on disk.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`none`
|
||||
|
||||
`-Dwith-libressl-suffix=$suffix`
|
||||
|
||||
This option is only used when `-Dwith-libressl-mode=shim`, and sets the
|
||||
suffix for the libraries that LSI will attempt to use when transforming
|
||||
requests for LibreSSL libraries.
|
||||
|
||||
This will transform `libssl.so.$VERSION` to `libssl-$suffix.so`, i.e.
|
||||
`libssl.so.37` would become `libssl-libressl.so`. This allows distros
|
||||
to provide up to date `libressl` and `openssl` builds in parallel to
|
||||
improve the security of games relying on LibreSSL.
|
||||
|
||||
The default value for this option is:
|
||||
|
||||
`-libressl`
|
||||
|
||||
## How LSI Works
|
||||
|
||||
LSI provides a /usr/bin/steam binary to be used in place of the existing Steam script, which will then correctly set up the environment before swapping the process for the Steam process.
|
||||
When using a full build of LSI, the bootstrap shim will force a correct environment, removing any issues that can cause various older SDL versions to kill Steam. Additionally it will then
|
||||
force `STEAM_RUNTIME=0` if this is set in the config (default behaviour).
|
||||
|
||||
When using the native runtime, and the `intercept` library is enabled, the LSI shim will also set up `LD_AUDIT` to use `liblsi-intercept.so`. This library will intercept all dynamic linking operations
|
||||
for the main Steam binaries and override their behaviour, allowing Steam to only load a handful of vendored libraries (`libav` fork) as well as its own private libraries. It is then forced to use
|
||||
system libraries for everything else. This means the Steam client, web helper, etc, will use the native SDL, X11, fixing many bugs with video playback, font rendering and such.
|
||||
|
||||
As of the `0.6` release of LSI, we now also support a `redirect` module. When enabled, the LSI shim will set `LD_PRELOAD` to use `liblsi-redirect.so`, which will conditionally enable it's own
|
||||
internal logic based on the game being played. This module currently overrides the `open()` and `fopen64()` system calls to apply dynamic bug fixes to games, and may be expanded in future to
|
||||
provide more fixes.
|
||||
|
||||
Currently the `redirect` module supports:
|
||||
|
||||
- ARK: Survival Evolved* (Use fixed shader asset from `TheCenter` DLC to fix invalid water appearance)
|
||||
- Project Highrise* (Fix crash where the game attempts to use a directory as a config file `prefs.txt`)
|
||||
|
||||
If you are packaging LSI for a distribution, please ensure you provide both a 32-bit and 64-bit build of the intercept library so that the entirety of Steam's library (`.so`) mechanism is tightly
|
||||
controlled by LSI. See the scripts in the root directory of this repository for examples of how to do this.
|
||||
|
||||
Configuration options can be placed in an INI-style configuration file in a series of locations, which are ordered by priority in a cascade:
|
||||
|
||||
~/.config/linux-steam-integration.conf
|
||||
/etc/linux-steam-integration.conf
|
||||
/usr/share/defaults/linux-steam-integration/linux-steam-integration.conf
|
||||
|
||||
The user configuration takes immediate priority. Secondly we have the system-wide configuration for affecting all accounts, and lastly the vendor configuration, which may be provided by the integrator.
|
||||
|
||||
Currently this INI file supports three options. The root section in this INI file must be `[Steam]`.
|
||||
|
||||
`use-native-runtime = $boolean`
|
||||
|
||||
If set to a true boolean value, (yes/true/on), the host OS's native runtime
|
||||
will be used instead of the Steam provided runtime. If this is set to
|
||||
a false boolean value (no/false/off), then the startup will be modified
|
||||
to export the relevant `LD_PRELOAD` and `STEAM_RUNTIME` settings.
|
||||
|
||||
The default value of this variable is `true`.
|
||||
|
||||
`force-32bit = $boolean`
|
||||
|
||||
If set to a true boolean value (yes/true/on), the shadowed Steam binary will
|
||||
be run via the `linux32` command. This will force the `steam` process
|
||||
and all children to believe they are running on a 32-bit system. This
|
||||
may be useful for 64-bit games that are buggy only on 64-bit.
|
||||
|
||||
If this is set to a false boolean value (no/false/off), then the
|
||||
shadowed Steam binary will be directly executed. Note that on 32-bit
|
||||
OSs this setting is ignored.
|
||||
|
||||
The default value of this variable is `false`.
|
||||
|
||||
`use-libintercept = $boolean`
|
||||
|
||||
If set to a true boolean value (yes/true/on), the `liblsi-intercept.so`
|
||||
library will be utilised to control dynamic linking within the Steam client
|
||||
and associated processes.
|
||||
|
||||
Note this requires `use-native-runtime` to be set.
|
||||
|
||||
The default value of this variable is `true`.
|
||||
|
||||
`use-libredirect = $boolean`
|
||||
|
||||
If set to a true boolean value (yes/true/on), the `liblsi-redirect.so`
|
||||
library will be utilised to apply "hot" workarounds to certain games to
|
||||
fix various runtime issues.
|
||||
|
||||
Note this requires `use-native-runtime` to be set.
|
||||
|
||||
The default value of this variable is `true`.
|
||||
|
||||
|
||||
## Common issues
|
||||
|
||||
Virtually all issues will come down to having the right dependencies. LSI puts an emphasis on
|
||||
host-first libraries, so make sure all the correct libraries are available for both 32-bit and
|
||||
64-bit.
|
||||
|
||||
Steam has both 32-bit and 64-bit processes/libraries, having the full dependency set for both
|
||||
the client and common games/engines is a must.
|
||||
|
||||
### Steam fails to launch with libintercept/native-runtime
|
||||
|
||||
Make sure you enable full debugging when first assigning dependencies to your runtime package:
|
||||
|
||||
```bash
|
||||
$ LSI_DEBUG=1 steam
|
||||
# If you use co-exist option:
|
||||
$ LSI_DEBUG=1 lsi-steam
|
||||
```
|
||||
|
||||
### liblsi-intercept regressing performance
|
||||
|
||||
There exists a bug in `glibc` which incorrectly configures profiling for all PLT calls when using `LD_AUDIT` (rtld-audit)
|
||||
even if the audit library doesn't implement `la_pltenter` or `la_pltexit`. This leads to a performance hit on every
|
||||
runtime call via PLT.
|
||||
|
||||
The issue was first reported to this project by @amonakov [here](https://github.com/solus-project/linux-steam-integration/issues/15).
|
||||
The upstream glibc issue is reported on the upstream glibc [bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15533).
|
||||
A patch to resolve the issue was submitted by @amonakov [here](https://sourceware.org/ml/libc-alpha/2013-05/msg00888.html).
|
||||
|
||||
If you are noticing performance regressions, you can:
|
||||
|
||||
- As a user: Disable `liblsi-intercept` via `lsi-settings`. This will hurt compatibility.
|
||||
- As a packager: Disable `liblsi-intercept` via build flags. This will hurt compatibility.
|
||||
- As a distribution integrator: Add weight to upstream issue and import patch into your distribution.
|
||||
This will retain LSI compatibility magic and mitigate performance issues.
|
||||
As an example, Solus has already [integrated the patch](https://dev.solus-project.com/R927:afa5b639e8a9b62618457a304d1e6fb42a9f2066).
|
||||
|
||||
The long term solution is to remove this burden from non-Solus Linux distributions, and for the Solus & LSI projects to
|
||||
provide a specialised runtime & strict LSI build via third party mechanisms so that all this work only needs doing once.
|
||||
This will help ensure the same gaming experience regardless of Linux distribution, remove all compatibility issues, and
|
||||
any pressures on distributions. Additionally this will allow even distributions not supporting multilib to provide a
|
||||
curated and well integrated gaming runtime.
|
||||
|
||||
|
||||
`* Some names may be claimed as the property of others.`
|
||||
@@ -1,20 +0,0 @@
|
||||
LSI is still in its infancy, currently only at a 0.1 release. The time to
|
||||
release was dramatic due to an absolute requirement for non-broken Steam
|
||||
to accompany the Solus 1.2 release
|
||||
|
||||
Going forward, there are more items that need implementing to start shaving
|
||||
more rough edges off of Linux gaming.
|
||||
|
||||
Immediate LSI worklist:
|
||||
|
||||
- [x] Add configurable shim to replace /usr/bin/steam, relying on shadowed launcher
|
||||
- [x] Add super-basic UI to configure said shim
|
||||
- [x] Shove out a 0.1 for Solus 1.2
|
||||
- [ ] Replace existing /usr/bin/steam entirely and decouple the tight runtime logic
|
||||
that is currently enforced.
|
||||
- [ ] Remove requirement for steam.sh $bindir/steam entirely - allowing parallel clients.
|
||||
LSI becomes more self contained and no longer needs to prop up Steam, but replaces
|
||||
much of the support tools.
|
||||
- [ ] Replace the existing Steam "run.sh" style launch facilities
|
||||
- [ ] Get to a point that current ubuntu12_32 runtime is no longer required or
|
||||
wanted.
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
autoreconf --force --install --symlink --warnings=all
|
||||
|
||||
args="\
|
||||
--sysconfdir=/etc \
|
||||
--localstatedir=/var \
|
||||
--prefix=/usr \
|
||||
--enable-silent-rules"
|
||||
|
||||
./configure CFLAGS="-g -O1 $CFLAGS" $args "$@"
|
||||
make clean
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
AC_INIT([linux-steam-integration], 0.2, [ikey@solus-project.com], [linux-steam-integration], [https://github.com/solus-project/linux-steam-integration/issues])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([-Wno-portability no-dist-gzip dist-xz foreign subdir-objects])
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC_STDC
|
||||
LT_PREREQ(2.2)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
AM_SILENT_RULES([yes])
|
||||
LT_INIT([disable-static])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
# Check if we're using the new C++ ABI, which will require LD_PRELOAD magic
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_MSG_CHECKING(['_GLIBCXX_USE_CXX11_ABI' value])
|
||||
AC_COMPUTE_INT([LSI_NEW_CXX_ABI], [_GLIBCXX_USE_CXX11_ABI], [[#include <string>]], [LSI_NEW_CXX_ABI=0])
|
||||
AC_MSG_RESULT([$LSI_NEW_CXX_ABI])
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
if test x$LSI_NEW_CXX_ABI = "x1"; then
|
||||
use_new_abi="yes"
|
||||
AC_DEFINE([LSI_USE_NEW_ABI], [1], [Using new C++ ABI])
|
||||
else
|
||||
use_new_abi="no"
|
||||
fi
|
||||
|
||||
# Source: https://mail.gnome.org/archives/commits-list/2012-September/msg01730.html
|
||||
# adl_RECURSIVE_EVAL(VALUE, RESULT)
|
||||
# =================================
|
||||
# Interpolate the VALUE in loop until it doesn't change,
|
||||
# and set the result to $RESULT.
|
||||
# WARNING: It's easy to get an infinite loop with some unsane input.
|
||||
# For example ${datadir} becomes ${datarootdir}, and then ${prefix}/share, and
|
||||
# finally ${prefix} is replaced by the prefix.
|
||||
AC_DEFUN([adl_RECURSIVE_EVAL],
|
||||
[_lcl_receval="$1"
|
||||
$2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix"
|
||||
test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
|
||||
_lcl_receval_old=''
|
||||
while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do
|
||||
_lcl_receval_old="[$]_lcl_receval"
|
||||
eval _lcl_receval="\"[$]_lcl_receval\""
|
||||
done
|
||||
echo "[$]_lcl_receval")`])
|
||||
|
||||
# Shadow location of real Steam
|
||||
AC_ARG_WITH([real-steam-binary], AS_HELP_STRING([--with-real-steam-binary],
|
||||
[the real Steam binary to use]), [steambin=${withval}],
|
||||
[steambin="$libdir/steam/steam"])
|
||||
|
||||
adl_RECURSIVE_EVAL(["$steambin"], [STEAMBIN])
|
||||
AC_SUBST(STEAMBIN)
|
||||
|
||||
AC_DEFINE_UNQUOTED(STEAM_BINARY, "$STEAMBIN",
|
||||
[The location of the real Steam binary])
|
||||
|
||||
# The LD_PRELOAD list required to integrate gracefully with the official Steam Runtime
|
||||
AC_ARG_WITH([preload-libs], AS_HELP_STRING([--with-preload-libs],
|
||||
[the preload libs to use with Steams own runtime]), [preloadlibs="${withval}"],
|
||||
[preloadlibs="/usr/\$LIB/libX11.so.6:/usr/\$LIB/libstdc++.so.6"])
|
||||
|
||||
AC_DEFINE_UNQUOTED([LSI_PRELOAD_LIBS], "$preloadlibs",
|
||||
[Libraries to preload with Steams runtime])
|
||||
|
||||
m4_define([gtk_required_version], [3.4.0])
|
||||
|
||||
# Check if frontend is requested
|
||||
have_frontend="no"
|
||||
AC_ARG_ENABLE(frontend, AS_HELP_STRING([--enable-frontend], [enable GTK frontend]))
|
||||
if test "x$enable_frontend" = "xyes" ; then
|
||||
PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= gtk_required_version])
|
||||
AC_DEFINE([HAVE_FRONTEND], [1], [Enabled GTK+ frontend])
|
||||
have_frontend="yes"
|
||||
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_FRONTEND], [test x$have_frontend = "xyes"])
|
||||
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([
|
||||
linux-steam-integration $VERSION
|
||||
========
|
||||
|
||||
prefix: ${prefix}
|
||||
libdir: ${libdir}
|
||||
sysconfdir: ${sysconfdir}
|
||||
exec_prefix: ${exec_prefix}
|
||||
bindir: ${bindir}
|
||||
datarootdir: ${datarootdir}
|
||||
|
||||
New C++ ABI: ${use_new_abi}
|
||||
Real Steam binary: ${STEAMBIN}
|
||||
GTK+ Frontend: ${have_frontend}
|
||||
preload-libs: ${preloadlibs}
|
||||
|
||||
compiler: ${CC}
|
||||
cflags: ${CFLAGS}
|
||||
ldflags: ${LDFLAGS}
|
||||
])
|
||||
@@ -0,0 +1,107 @@
|
||||
[Desktop Entry]
|
||||
Name=LSI Steam
|
||||
Comment=Launch Steam via LSI
|
||||
Exec=/usr/bin/lsi-steam %U
|
||||
Icon=steam
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;FileTransfer;Game;
|
||||
MimeType=x-scheme-handler/steam;
|
||||
Actions=Store;Community;Library;Servers;Screenshots;News;Settings;BigPicture;Friends;
|
||||
|
||||
[Desktop Action Store]
|
||||
Name=Store
|
||||
Name[de]=Shop
|
||||
Name[es]=Tienda
|
||||
Name[fr]=Magasin
|
||||
Name[it]=Negozio
|
||||
Name[pt]=Loja
|
||||
Name[ru]=Магазин
|
||||
Name[zh_CN]=商店
|
||||
Name[zh_TW]=商店
|
||||
Exec=lsi-steam steam://store
|
||||
|
||||
[Desktop Action Community]
|
||||
Name=Community
|
||||
Name[es]=Comunidad
|
||||
Name[fr]=Communauté
|
||||
Name[it]=Comunità
|
||||
Name[pt]=Comunidade
|
||||
Name[ru]=Сообщество
|
||||
Name[zh_CN]=社区
|
||||
Name[zh_TW]=社群
|
||||
Exec=lsi-steam steam://url/SteamIDControlPage
|
||||
|
||||
[Desktop Action Library]
|
||||
Name=Library
|
||||
Name[de]=Bibliothek
|
||||
Name[es]=Biblioteca
|
||||
Name[fr]=Bibliothèque
|
||||
Name[it]=Libreria
|
||||
Name[pt]=Biblioteca
|
||||
Name[ru]=Библиотека
|
||||
Name[zh_CN]=库
|
||||
Name[zh_TW]=遊戲庫
|
||||
Exec=lsi-steam steam://open/games
|
||||
|
||||
[Desktop Action Servers]
|
||||
Name=Servers
|
||||
Name[de]=Server
|
||||
Name[es]=Servidores
|
||||
Name[fr]=Serveurs
|
||||
Name[it]=Server
|
||||
Name[pt]=Servidores
|
||||
Name[ru]=Серверы
|
||||
Name[zh_CN]=服务器
|
||||
Name[zh_TW]=伺服器
|
||||
Exec=lsi-steam steam://open/servers
|
||||
|
||||
[Desktop Action Screenshots]
|
||||
Name=Screenshots
|
||||
Name[es]=Capturas
|
||||
Name[fr]=Captures d'écran
|
||||
Name[it]=Screenshot
|
||||
Name[ru]=Скриншоты
|
||||
Name[zh_CN]=截图
|
||||
Name[zh_TW]=螢幕擷圖
|
||||
Exec=lsi-steam steam://open/screenshots
|
||||
|
||||
[Desktop Action News]
|
||||
Name=News
|
||||
Name[de]=Neuigkeiten
|
||||
Name[es]=Noticias
|
||||
Name[fr]=Actualités
|
||||
Name[it]=Notizie
|
||||
Name[pt]=Notícias
|
||||
Name[ru]=Новости
|
||||
Name[zh_CN]=新闻
|
||||
Name[zh_TW]=新聞
|
||||
Exec=lsi-steam steam://open/news
|
||||
|
||||
[Desktop Action Settings]
|
||||
Name=Settings
|
||||
Name[de]=Einstellungen
|
||||
Name[es]=Parámetros
|
||||
Name[fr]=Paramètres
|
||||
Name[it]=Impostazioni
|
||||
Name[pt]=Configurações
|
||||
Name[ru]=Настройки
|
||||
Name[zh_CN]=设置
|
||||
Name[zh_TW]=設定
|
||||
Exec=lsi-steam steam://open/settings
|
||||
|
||||
[Desktop Action BigPicture]
|
||||
Name=Big Picture
|
||||
Exec=lsi-steam steam://open/bigpicture
|
||||
|
||||
[Desktop Action Friends]
|
||||
Name=Friends
|
||||
Name[de]=Freunde
|
||||
Name[es]=Amigos
|
||||
Name[fr]=Amis
|
||||
Name[it]=Amici
|
||||
Name[pt]=Amigos
|
||||
Name[ru]=Друзья
|
||||
Name[zh_CN]=好友
|
||||
Name[zh_TW]=好友
|
||||
Exec=lsi-steam steam://open/friends
|
||||
@@ -0,0 +1,17 @@
|
||||
appsdir = join_paths(datadir, 'applications')
|
||||
|
||||
# If frontend is enabled, install lsi-settings.desktop
|
||||
if with_frontend == true
|
||||
install_data(
|
||||
'lsi-settings.desktop',
|
||||
install_dir: appsdir,
|
||||
)
|
||||
endif
|
||||
|
||||
# If we need to co-exist, install alternative .desktop file (not conflicting with Steam)
|
||||
if shim_behaviour == 'co-exist'
|
||||
install_data(
|
||||
'lsi-steam.desktop',
|
||||
install_dir: appsdir,
|
||||
)
|
||||
endif
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
project(
|
||||
'linux-steam-integration',
|
||||
['c'],
|
||||
version: '0.6',
|
||||
license: [
|
||||
'LGPL-2.1',
|
||||
],
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
am_cflags = [
|
||||
'-fstack-protector',
|
||||
'-pedantic',
|
||||
'-Wstrict-prototypes',
|
||||
'-Wundef',
|
||||
'-fno-common',
|
||||
'-Werror-implicit-function-declaration',
|
||||
'-Wformat',
|
||||
'-Wformat-security',
|
||||
'-Werror=format-security',
|
||||
'-Wno-conversion',
|
||||
'-Wunused-variable',
|
||||
'-Wunreachable-code',
|
||||
'-Wall',
|
||||
'-W',
|
||||
'-D_FORTIFY_SOURCE=2',
|
||||
]
|
||||
|
||||
add_global_arguments(am_cflags, language: 'c')
|
||||
|
||||
dep_gtk3 = dependency('gtk+-3.0', version: '>= 3.4.0')
|
||||
|
||||
cdata = configuration_data()
|
||||
|
||||
cdata.set_quoted('PACKAGE_NAME', meson.project_name())
|
||||
|
||||
prefix = get_option('prefix')
|
||||
datadir = join_paths(prefix, get_option('datadir'))
|
||||
vendordir = join_paths(datadir, 'defaults', meson.project_name())
|
||||
sysconfdir = join_paths(prefix, get_option('sysconfdir'))
|
||||
localedir = join_paths(prefix, get_option('localedir'))
|
||||
cdata.set_quoted('SYSTEMCONFDIR', sysconfdir)
|
||||
cdata.set_quoted('VENDORDIR', vendordir)
|
||||
cdata.set_quoted('LOCALEDIR', localedir)
|
||||
cdata.set_quoted('GETTEXT_PACKAGE', meson.project_name())
|
||||
|
||||
# Configurables
|
||||
cdata.set_quoted('LSI_PRELOAD_LIBS', get_option('with-preload-libs'))
|
||||
cdata.set_quoted('STEAM_BINARY', get_option('with-steam-binary'))
|
||||
|
||||
shim_behaviour = get_option('with-shim')
|
||||
if shim_behaviour == 'replacement'
|
||||
cdata.set('REPLACE_STEAM', '1')
|
||||
endif
|
||||
|
||||
with_libintercept = get_option('with-libintercept')
|
||||
if with_libintercept == true
|
||||
cdata.set('HAVE_LIBINTERCEPT', '1')
|
||||
endif
|
||||
|
||||
with_libredirect = get_option('with-libredirect')
|
||||
if with_libredirect == true
|
||||
cdata.set('HAVE_LIBREDIRECT', '1')
|
||||
endif
|
||||
|
||||
with_frontend = get_option('with-frontend')
|
||||
|
||||
if get_option('with-new-libcxx-abi') == true
|
||||
cdata.set('LSI_USE_NEW_ABI', '1')
|
||||
endif
|
||||
|
||||
with_libressl_mode = get_option('with-libressl-mode')
|
||||
if with_libressl_mode == 'native'
|
||||
cdata.set('LSI_LIBRESSL_MODE_NATIVE', '1')
|
||||
cdata.set('LSI_OVERRIDE_LIBRESSL', '1')
|
||||
elif with_libressl_mode == 'shim'
|
||||
cdata.set('LSI_LIBRESSL_MODE_SHIM', '1')
|
||||
cdata.set('LSI_OVERRIDE_LIBRESSL', '1')
|
||||
cdata.set_quoted('LSI_LIBRESSL_SUFFIX', get_option('with-libressl-suffix'))
|
||||
else
|
||||
message('LibreSSL mode isn\'t configured which may impact security')
|
||||
endif
|
||||
|
||||
config_h = configure_file(
|
||||
configuration: cdata,
|
||||
output: 'config.h',
|
||||
)
|
||||
config_h_dir = include_directories('.')
|
||||
|
||||
subdir('data')
|
||||
subdir('src')
|
||||
subdir('po')
|
||||
@@ -0,0 +1,14 @@
|
||||
option('with-shim', type : 'combo', choices : ['replacement', 'co-exist', 'none'], value: 'replacement',
|
||||
description : 'control how the shim is deployed')
|
||||
option('with-steam-binary', type: 'string', description: 'Set the path to the Steam binary', value: '/usr/lib/steam/steam')
|
||||
option('with-frontend', type: 'boolean', description: 'Build the LSI Settings UI', value: false)
|
||||
option('with-preload-libs', type: 'string', description: 'Colon separated list of libraries required to launch Steam games',
|
||||
value: '/usr/\$LIB/libxcb.so.1:/usr/\$LIB/libX11.so.6:/usr/\$LIB/libstdc++.so.6')
|
||||
option('with-libintercept', type: 'boolean', description: 'Enable libintercept library for controlling Steam linking', value: true)
|
||||
option('with-libredirect', type: 'boolean', description: 'Enable libredirect library for fine-tuning Steam games', value: true)
|
||||
option('with-new-libcxx-abi', type: 'boolean', description: 'Enable when using the new libstdc++ ABI', value: false)
|
||||
|
||||
option('with-libressl-mode', type: 'combo', choices: ['native', 'shim', 'none'], value: 'none',
|
||||
description: 'Control how LibreSSL replacements are performed')
|
||||
option('with-libressl-suffix', type: 'string', value: '-libressl',
|
||||
description: 'Suffix for shim LibreSSL library when using --with-libressl-mode=shim')
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [[ ! -d buildroot/build32 ]]; then
|
||||
CC="gcc -m32" linux32 meson buildroot/build32 -Dwith-libressl-mode=shim --prefix=/usr --sysconfdir=/etc --datadir=/usr/share --libdir=/usr/lib32 -Dwith-shim=none -Dwith-new-libcxx-abi=true --buildtype debugoptimized
|
||||
fi
|
||||
|
||||
if [[ ! -d buildroot/build64 ]]; then
|
||||
meson buildroot/build64 -Dwith-libressl-mode=shim --prefix=/usr --sysconfdir=/etc --datadir=/usr/share --libdir=/usr/lib64 -Dwith-shim=replacement -Dwith-steam-binary=/usr/lib64/steam/steam -Dwith-frontend=true -Dwith-new-libcxx-abi=true --buildtype debugoptimized
|
||||
fi
|
||||
|
||||
ninja -C buildroot/build32
|
||||
ninja -C buildroot/build64
|
||||
|
||||
sudo ninja -C buildroot/build32 install
|
||||
sudo ninja -C buildroot/build64 install
|
||||
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
# Script for ikey because he went with meson. *shrug*
|
||||
VERSION="0.6"
|
||||
NAME="linux-steam-integration"
|
||||
git-archive-all.sh --format tar --prefix ${NAME}-${VERSION}/ --verbose -t HEAD ${NAME}-${VERSION}.tar
|
||||
xz -9 "${NAME}-${VERSION}.tar"
|
||||
|
||||
gpg --armor --detach-sign "${NAME}-${VERSION}.tar.xz"
|
||||
gpg --verify "${NAME}-${VERSION}.tar.xz.asc"
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
ar
|
||||
ca_ES
|
||||
ca
|
||||
cs
|
||||
da_DK
|
||||
de
|
||||
en_GB
|
||||
es_419
|
||||
es_AR
|
||||
es_MX
|
||||
es_PE
|
||||
fi
|
||||
fr_FR
|
||||
he
|
||||
id_ID
|
||||
it_IT
|
||||
ne_NP
|
||||
nl_BE
|
||||
nl_NL
|
||||
pl_PL
|
||||
pl
|
||||
pt_BR
|
||||
pt_PT
|
||||
ro_RO
|
||||
sv_SE
|
||||
zh_CN
|
||||
@@ -0,0 +1 @@
|
||||
src/frontend/main-window.c
|
||||
@@ -0,0 +1,81 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Ahmed Lemine <aljakany@gmail.com>, 2017\n"
|
||||
"Language-Team: Arabic (https://www.transifex.com/solus-project/teams/68407/ar/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ar\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "دمج ستيم® ولينكس"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"التحكم في سلوك عميل ستيم والألعاب. لن تكون الإعدادات سارية المفعول ما لم يتم"
|
||||
" إعادة تشغيل عميل ستيم. استخدم خيار \"الخروج من ستيم\" للتأكد من إغلاقه."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "استخدم زمن تشغيل أصيل"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "بدّل بين زمن التشغيل الأصيل وزمن التشغيل المرفق مع ستيم."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "تم تعطيل هذا الخيار لأن النظام أساساً ذو معمارية 32 بت"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr "قد يصلح هذا بعض الألعاب المعطلة، لكن سيعطل متصفح متجر ستيم."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "افرض وضع 32 بت لستيم"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "استخدم مكتبة الاعتراض"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"أجبر تطبيقات ستيم على استخدام مزيد من المكتبات الأصيلة لزيادة التوافق إلى "
|
||||
"أقصى درجة."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "استخدم مكتبة إعادة التوجيه"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "تجاوز استدعاءات النظام لإصلاح مشكلات معروفة في بعض نسخ لينكس."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "فشل في حفظ الإعدادات"
|
||||
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Davidmp <medipas@gmail.com>, 2017\n"
|
||||
"Language-Team: Catalan (https://www.transifex.com/solus-project/teams/68407/ca/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ca\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integració de Linux Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controleu el comportament del client i dels jocs d'Steam. La configuració no"
|
||||
" tindrà efecte fins que no es reiniciï el client d'Steam. Useu l'opció "
|
||||
"\"Surt de l'Steam\" per assegurar-vos que es tanqui."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usa l'entorn d'execució natiu"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Canvieu entre l'entorn natiu i l'entorn d'Steam agrupat."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Aquesta opció s'ha inhabilitat ja que el sistema ja és de 32 bits."
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Això pot solucionar alguns jocs trencats, però inhabilitarà el navegador de "
|
||||
"la botiga d'Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Força el mode de 32 bits per a l'Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usa la biblioteca d'intercepció"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Força que les aplicacions de l'Steam usin més biblioteques natives per "
|
||||
"maximitzar la compatibilitat."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usa la biblioteca de redirecció"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Anul·la les crides de sistema per corregir errors coneguts en algunes "
|
||||
"versions de Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Ha fallat desar la configuració"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Davidmp <medipas@gmail.com>, 2017\n"
|
||||
"Language-Team: Catalan (Spain) (https://www.transifex.com/solus-project/teams/68407/ca_ES/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ca_ES\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integració de Linux Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controleu el comportament del client i dels jocs d'Steam. La configuració no"
|
||||
" tindrà efecte fins que no es reiniciï el client d'Steam. Useu l'opció "
|
||||
"\"Surt de l'Steam\" per assegurar-vos que es tanqui."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usa l'entorn d'execució natiu"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Canvieu entre l'entorn natiu i l'entorn d'Steam agrupat."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Aquesta opció s'ha inhabilitat ja que el sistema ja és de 32 bits."
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Això pot solucionar alguns jocs trencats, però inhabilitarà el navegador de "
|
||||
"la botiga d'Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Força el mode de 32 bits per a l'Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usa la biblioteca d'intercepció"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Força que les aplicacions de l'Steam usin més biblioteques natives per "
|
||||
"maximitzar la compatibilitat."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usa la biblioteca de redirecció"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Anul·la les crides de sistema per corregir errors coneguts en algunes "
|
||||
"versions de Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Ha fallat desar la configuració"
|
||||
@@ -0,0 +1,85 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Ondřej Pucholt <o.pucholt@windowslive.com>, 2017\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/solus-project/teams/68407/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integrace služby Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Ovládá chování her a klienta služby Steam. Změny nastavení se projeví až po "
|
||||
"restartování služby. Pro její zaručené ukončení zvolte možnost \"Ukončit "
|
||||
"službu Steam\"."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Používat nativní běhové prostředí"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Přepíná mezi nativním a přibaleným běhovým prostředím služby Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Tato volba není dostupná, protože systém už je 32bitový"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Umožňuje obejít některé problémy se hrami, ale deaktivuje prohlížeč obchodu "
|
||||
"služby Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Přinutit službu Steam používat 32bitový režim"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Používat knihovnu pro zachytávání"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Přinutit programy ze služby Steam používat více nativních knihoven pro "
|
||||
"zajištění maximální kompatibility."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Používat knihovnu pro přesměrování"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Přepsáním systémových volání opravit známé chyby v linuxových portech her."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Uložení konfigurace selhalo"
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Yavuznie <y.z@live.dk>, 2017\n"
|
||||
"Language-Team: Danish (Denmark) (https://www.transifex.com/solus-project/teams/68407/da_DK/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da_DK\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integration med Linux Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Styr opførslen af Steam-klienten og spil. Indstillingerne vil ikke træde i "
|
||||
"kraft før Steam-klienten er blevet genstartet. Brug 'Afslut Steam' for af "
|
||||
"sikre at programmet lukkes."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Brug nativ runtime"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Skift mellem nativ runtime og den runtime som følger med Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr ""
|
||||
"Denne mulighed er blevet deaktiveret eftersom systemet allerede er 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Det løser muligvis problemer for nogle ødelagte spil, til gengæld "
|
||||
"deaktiveres Steam butik-browseren."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Tving 32-bit-tilstand for Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Brug intercept-biblioteket"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Tving Steam-programmer til at bruge flere native biblioteker for at "
|
||||
"maksimere kompatibilitet."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Brug redirect-biblioteket"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "Tilsidesæt systemkald for at rette kendte fejl i nogle Linux-porte."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Kunne ikke gemme konfiguration"
|
||||
@@ -0,0 +1,88 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Thomas Staudinger <staudi.kaos@gmail.com>, 2017\n"
|
||||
"Language-Team: German (https://www.transifex.com/solus-project/teams/68407/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Beeinflusse das Verhalten des Steam-Clients und von Spielen. Die "
|
||||
"Einstellungen werden erst aktiv, nachdem der Steam-Client neu gestartet "
|
||||
"wurde. Nutze 'Steam beenden', um sicherzugehen, dass es beendet wird."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Nutze native Laufzeitumgebung"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Wechsle zwischen der nativen Laufzeitumgebung und der Steam-"
|
||||
"Laufzeitumgebung."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Diese Option ist deaktiviert, da dies bereits ein 32-bit System ist."
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Dies behebt möglicherweise Fehler bei kaputten Steam-Spielen, wird aber den "
|
||||
"Steam Store Browser deaktivieren."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Erzwinge 32-bit-Modus für Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Nutze die Intercept-Bibliothek"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Zwinge Steam Anwendungen dazu, mehr native Bibliotheken zu nutzen, um die "
|
||||
"Kompatibilität zu maximieren."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Nutze die Redirect-Bibliothek"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Überschreibe Systemcalls, um bekannte Bugs in manchen Linux-Ports zu "
|
||||
"beheben."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Konfiguration konnte nicht gespeichert werden"
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: \n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Use native runtime"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Switch between the native runtime and the bundled Steam runtime."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "This option has been disabled as the system is already 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Force 32-bit mode for Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Use the intercept library"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Use the redirect library"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "Override system calls to fix known bugs in some Linux ports."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Failed to save configuration"
|
||||
@@ -0,0 +1,87 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Víctor Rodríguez <vhugo642@gmail.com>, 2017\n"
|
||||
"Language-Team: Spanish (Latin America) (https://www.transifex.com/solus-project/teams/68407/es_419/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_419\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla el comportamiento del cliente y los juegos de Steam. La "
|
||||
"configuración no tendrá efecto hasta que el cliente de Steam se reinicie. "
|
||||
"Use la opción 'Salir de Steam' para asegurarse de que se cierre."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar tiempo de ejecución del sistema"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Cambie entre el tiempo de ejecución del sistema y el incluido por Steam"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Esta opción ha sido desactivada ya que el sistema ya es de 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Esto puede mejorar algunos juegos rotos, pero desactivará el navegador de la"
|
||||
" tienda de Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forzar modo de 32-bit para Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Utilizar la biblioteca de intercepción"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forzar a las aplicaciones de Steam a usar más librerías nativas para "
|
||||
"maximizar la compatibilidad."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Utilizar la biblioteca de redirección"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Anular las llamadas del sistema para solucionar algunos problemas conocidos "
|
||||
"en adaptaciones de Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Error al guardar la configuración"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Abe Linux <m.delvalle01@gmail.com>, 2017\n"
|
||||
"Language-Team: Spanish (Argentina) (https://www.transifex.com/solus-project/teams/68407/es_AR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_AR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integración Steam® para Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla el comportamiento del cliente y juegos de Steam. Las preferencias "
|
||||
"no tomarán efecto hasta que el cliente de Steam sea reiniciado. Usa la "
|
||||
"opción \"Salir de Steam\" para asegurarte de que se cierre."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar el entorno nativo"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Cambiar entre el entorno nativo y el incluido por Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Esta opción ha sido deshabilitada dado que el sistema ya es de 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Esto puede solucionar algunos juegos que no funcionen, pero deshabilitará la"
|
||||
" tienda Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forzar modo 32-bit para Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usar la librería intercept"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forzar a las aplicaciones de Steam a utilizar más librerías nativas para "
|
||||
"maximizar la compatibilidad."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usar la librería intercept"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Sobrescribir llamadas de sistema para corregir problemas conocidos en "
|
||||
"algunas adaptaciones de juegos para Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Falló en guardar la configuración"
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Fernando Macias <FernandoMaciasR@yahoo.com.mx>, 2017\n"
|
||||
"Language-Team: Spanish (Mexico) (https://www.transifex.com/solus-project/teams/68407/es_MX/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_MX\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integración de Steam® con Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla el comportamiento del cliente y los juegos de Steam. Los ajustes no"
|
||||
" tendrán efecto hasta que el cliente de Steam sea reiniciado. Use la opción "
|
||||
"de 'Salir de Steam' para asegurarse de que sea cerrado."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar tiempo de ejecución nativo"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Cambia entre el tiempo de ejecución nativo y el tiempo de ejecución incluido"
|
||||
" en Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr ""
|
||||
"Esta opción ha sido deshabilitada debido a que el sistema ya es de 32 bits"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Esto puede solucionar algunos juegos que no funcionen, pero desactivará el "
|
||||
"navegador de la tienda de Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forzar modo de 32 bits para Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usar la librería de intercepción"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forzar a las aplicaciones de Steam a que utilizen más librerias nativas para"
|
||||
" maximizar la compatibilidad."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usar la librería de redirección"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Anular las llamadas del sistema para corregir errores conocidos en algunos "
|
||||
"puertos Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "No se pudo guardar la configuración"
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Víctor Rodríguez <vhugo642@gmail.com>, 2017\n"
|
||||
"Language-Team: Spanish (Peru) (https://www.transifex.com/solus-project/teams/68407/es_PE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_PE\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla el comportamiento del cliente y los juegos de Steam. La "
|
||||
"configuración no tendrá efecto hasta que el cliente de Steam se reinicie. "
|
||||
"Use la opción 'Salir de Steam' para asegurarse de que se cierre."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar tiempo de ejecución del sistema"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Cambie entre el tiempo de ejecución del sistema y el incluido por Steam"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Esta opción ha sido desactivada ya que el sistema ya es de 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Esto puede mejorar algunos juegos rotos, pero desactivará el navegador de la"
|
||||
" tienda de Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forzar modo de 32-bit para Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usar la librería de intercepción"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forzar a las aplicaciones de Steam a usar más librerías del sistema para "
|
||||
"maximizar la compatibilidad."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usar la librería de intercepción"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Anular las llamadas del sistema para solucionar algunos problemas conocidos "
|
||||
"en adaptaciones de Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Error al guardar la configuración"
|
||||
@@ -0,0 +1,88 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Kim Kröger <kroger.kim@gmail.com>, 2017\n"
|
||||
"Language-Team: Finnish (https://www.transifex.com/solus-project/teams/68407/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integraatio"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Ohjaa Steam-sovelluksen ja -pelien toimintaa. Asetukset tulevat voimaan "
|
||||
"vasta Steam-sovelluksen uudelleenkäynnistyksen myötä. Käytä \"Sulje Steam\" "
|
||||
"-toimintoa varmistaaksesi sen sulkeutumisen."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Käytä paikallista ohjelmakirjastoa"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Vaihda paikallisen ohjelmakirjaston ja Steamin mukana tulevan "
|
||||
"ohjelmakirjaston välillä."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Tämä asetus ei ole käytössä, koska järjestelmä on jo 32-bittinen"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Tämä voi väliaikaisesti korjata joidenkin pelien yhteensopivuusongelmat, "
|
||||
"mutta ottaa myös Steamin Kaupan pois käytöstä."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Pakottaa 32-bittisen tilan Steamille"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Käytä intercept-kirjastoa"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Pakottaa Steamin sovellusten käyttämään enemmän paikallisia "
|
||||
"ohjelmakirjastoja yhteensopivuuden maksimoimiseksi."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Käytä redirect-kirjastoa"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Ohittaa järjestelmän kutsut tunnettujen ongelmien korjaamiseksi joissakin "
|
||||
"peleissä."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Asetusten tallentaminen epäonnistui"
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Serge <vanmechelen.serge@gmail.com>, 2017\n"
|
||||
"Language-Team: French (France) (https://www.transifex.com/solus-project/teams/68407/fr_FR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr_FR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Intégration Steam® Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Contrôle le comportement du client et des jeux Steam. Les paramètres ne "
|
||||
"prendront effet qu'après le redémarrage du client Steam. Utilisez l'option "
|
||||
"'Quitter Steam' pour vous assurer que l'application a bien été arrêtée."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Utiliser l'environnement d'exécution natif"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Basculer entre l'environnement d'exécution natif et l'environnement "
|
||||
"d'exécution Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Cette option a été désactivée car le système est déjà en 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Ceci permet d'éviter des problèmes rencontrés avec certains jeux mais "
|
||||
"désactive le magasin Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forcer le mode 32-bit pour Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Utiliser la bibliothèque d'interception"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Obliger les applications Steam à utiliser davantage de bibliothèques natives"
|
||||
" pour maximiser la compatibilité."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Utiliser la bibliothèque de redirection"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Remplacer les appels système pour corriger les bogues connus pour certains "
|
||||
"ports sous Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Echec dans la sauvegarde de la configuration"
|
||||
@@ -0,0 +1,81 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Moshe Sh <7moshe7@gmail.com>, 2017\n"
|
||||
"Language-Team: Hebrew (https://www.transifex.com/solus-project/teams/68407/he/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: he\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "שילוב לינוקס וסטים "
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"שליטה על ההתנהגות של Steam Client ומשחקים. ההגדרות לא יכנסו לתוקף עד להפעלה "
|
||||
"מחדש של Steam Client. מומלץ להשתמש באופציה 'יציאה מסטים' על מנת לוודא שנסגר."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "שימוש בהרצה מקומית"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "החלפה בין הרצה מקומית להרצה של סטים."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "אפשרות זו הושבתה מאחר שהמערכת כבר 32 סיביות"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"פעולה זו עשויה לעקוף בעיה של כמה משחקים לא תקינים, אבל ישבית את הדפדפן של "
|
||||
"חנות סטים."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "הכרח מצב 32 סיביות עבור סטים"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "שימוש בספריית intercept"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr "הכרח יישומי סטים להשתמש בספריות מקומיות כדי להגדיל את התאימות."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "שימוש בספריית redirect"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "מעקף לקריאות המערכת כדי לתקן באגים ידועים בכמה יציאות לינוקס."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "שמירת ההגדרות נכשלה"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Yurizal Susanto <rizal.sagi@gmail.com>, 2017\n"
|
||||
"Language-Team: Indonesian (Indonesia) (https://www.transifex.com/solus-project/teams/68407/id_ID/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: id_ID\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integrasi Steam® Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Atur sifat klien Steam dan permainan. Pengaturan tidak akan berlaku sebelum "
|
||||
"klien Steam dimulai ulang. Gunakan pilihan 'Exit Steam' untuk memastikan "
|
||||
"klien tertutup."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Gunakan runtime bawaan"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Tukar antara runtime bawaan dan runtime yang dibundel Steam"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Pilihan ini dimatikan karena sistem sudah 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Ini bisa menyelesaikan masalah pada beberapa permainan, tapi akan "
|
||||
"menonaktifkan penjelajahan toko Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Paksa mode 32-bit untuk Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Gunakan pustaka pencegat"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Paksa aplikasi Steam untuk menggunakan lebih banyak pustaka bawaan untuk "
|
||||
"memaksimalkan kompabilitas."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Gunakan pustaka pengalihan"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Timpa panggilan sistem untuk memperbaiki bug yang diketahui di beberapa port"
|
||||
" Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Gagal menyimpan konfigurasi"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Fabio Forni <fabio94xx@gmail.com>, 2017\n"
|
||||
"Language-Team: Italian (Italy) (https://www.transifex.com/solus-project/teams/68407/it_IT/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it_IT\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controlla il comportamento dei giochi e del client Steam. Le impostazioni "
|
||||
"non avranno effetto finché il client Steam non sarà riavviato. Usa l'opzione"
|
||||
" \"Esci da Steam\" per assicurarti che venga davvero chiuso."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Use ambiente di runtime nativo"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Scegli tra l'ambiente di runtime nativo e quello integrato in Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Questa opzione è disabilitata perché il sistema è già a 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Può correggere alcuni giochi non funzionanti, ma disabiliterà la navigazione"
|
||||
" nel negozio Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forza Steam a 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usa la libreria di intercettazione"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forza le applicazioni di Steam a usare ancor più librerie native per "
|
||||
"massimizzare la compatibilità."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usa la libreria di redirezione"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Sostituisce le chiamate di sistema per correggere i bug noti di alcuni "
|
||||
"porting su Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Errore durante il salvataggio della configurazione"
|
||||
@@ -0,0 +1,76 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,3 @@
|
||||
i18n = import('i18n')
|
||||
|
||||
i18n.gettext(meson.project_name(), preset: 'glib')
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Rabin Adhikari <rabin.adk1@gmail.com>, 2017\n"
|
||||
"Language-Team: Nepali (Nepal) (https://www.transifex.com/solus-project/teams/68407/ne_NP/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ne_NP\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "लिनक्स स्टिम® एकीकरण"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"स्टिम क्लाइन्ट र खेलहरूको व्यवहार नियन्त्रण गर्नुहोस्। स्टिम क्लाइन्ट पुन: "
|
||||
"सुरु नभएसम्म सेटिङहरूमा प्रभाव पर्ने छैन। यो बन्द गर्न सुनिश्चित गर्नको लागि"
|
||||
" 'बाहिर निस्कनुहोस्' विकल्प प्रयोग गर्नुहोस्।"
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "मूल रनटाइम प्रयोग गर्नुहोस्"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "मूल रनटाइम र बन्डल स्टिम रनटाइम बीच स्विच गर्नुहोस्।"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "यो विकल्प असक्षम गरिएको छ किनभने प्रणाली पहिले नै 32-बिट छ"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"यसले केही बिच्छेद खेलहरूको गर्न वैकल्पिक समाधान गर्न सक्दछ, तर स्टिम भण्डार "
|
||||
"ब्राउजर असक्षम पार्नेछ।"
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "स्टिमको लागि 32-बिट मोड बल गर्नुहोस्"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "इन्टरसेप्ट लाइब्रेरी प्रयोग गर्नुहोस्"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"अनुकूलता अधिकतम गर्नका लागी थप मूल पुस्तकालयहरू प्रयोग गर्न स्टिम "
|
||||
"एप्लिकेसनहरूलाई बल गर्नुहोस्।"
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "पुन: निर्देशित पुस्तकालय प्रयोग गर्नुहोस्"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"केहि लिनक्स पोर्टहरूमा ज्ञात बगहरू ठीक गर्न प्रणाली कलहरू ओभरराइड गर्नुहोस्।"
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "कन्फिगरेसन सुरक्षित गर्न असफल भयो"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Geert Verheyde <geert.verheyde@gmail.com>, 2017\n"
|
||||
"Language-Team: Dutch (Belgium) (https://www.transifex.com/solus-project/teams/68407/nl_BE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: nl_BE\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Beheer het gedrag van de Steam Client en games. Wijzigingen zijn pas "
|
||||
"effectief na het herstarten van de Steam Client. Gebruik de \"Exit Steam\" "
|
||||
"optie om definitief af te sluiten."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Gebruik de systeemeigen runtime"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Wissel tussen de systeemeigen runtime en de gebundelde Steam runtime"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Deze optie werd uitgezet omdat het systeem reeds 32-bit is"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Dit kan gebroken games doen werken, maar zal de Steam store browser "
|
||||
"uitzetten."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forceer 32-bit modus voor Steam."
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Gebruik de opvangende bibliotheek"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forceer Steam toepassingen meer systeemeigen bibliotheken te gebruiken om de"
|
||||
" compatibiliteit te maximaliseren"
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Gebruik de omleidende bibliotheek"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Negeer systeemoproepen om gekende fouten te herstellen in bepaalde Linux "
|
||||
"ports"
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Het opslaan van de configuratie is mislukt."
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Heimen Stoffels <vistausss@outlook.com>, 2017\n"
|
||||
"Language-Team: Dutch (Netherlands) (https://www.transifex.com/solus-project/teams/68407/nl_NL/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: nl_NL\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Beheer het gedrag van de Steam-client en spellen. De wijzigingen zijn pas "
|
||||
"effectief na het herstarten van de Steam-client. Gebruik de \"Steam "
|
||||
"afsluiten\"-optie om Steam definitief af te sluiten."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Gebruik de systeemeigen runtime"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Wissel tussen de systeemeigen runtime en de gebundelde Steam runtime"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Deze optie is uitgeschakeld omdat het systeem reeds 32-bit is"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Dit kan gebroken spellen doen werken, maar zal de Steam store browser "
|
||||
"uitschakelen."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forceer 32-bitmodus voor Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Gebruik de opvangende bibliotheek"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forceer Steam-toepassingen meer systeemeigen bibliotheken te gebruiken om de"
|
||||
" compatibiliteit te maximaliseren."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Gebruik de omleidende bibliotheek"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Negeer systeemoproepen om bekende fouten te herstellen in bepaalde Linux-"
|
||||
"ports"
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Het opslaan van de configuratie is mislukt"
|
||||
@@ -0,0 +1,88 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Kacper Herchel <kacperski1@gmail.com>, 2017\n"
|
||||
"Language-Team: Polish (https://www.transifex.com/solus-project/teams/68407/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pl\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integracja Linuksa ze Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Zarządzaj zachowaniem klienta Steam i gier. Ustawienia dadzą efekt dopiero "
|
||||
"po zrestartowaniu klienta Steam. Użyj opcji „Zamknij Steam” aby upewnić się,"
|
||||
" że klient został zamknięty."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Używaj natywnego środowiska"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Przełączaj się między natywnym środowiskiem uruchomieniowym i wersją "
|
||||
"dołączaną do klienta Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Ta opcja została zablokowana, ponieważ używany system jest 32-bitowy"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"To może naprawić działanie niektórych gier, ale wyłączy możliwość "
|
||||
"przeglądania sklepu Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Wymuś tryb 32-bitowy dla Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Używaj biblioteki przechwytującej"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Wymusza na grach Steam używanie większej ilości natywnych bibliotek, co "
|
||||
"zwiększa kompatybilność."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Używaj biblioteki przekierowującej"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Nadpisuje wywołania systemowe, aby poprawić błędy w niektórych linuksowych "
|
||||
"portach."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Nie udało się zapisać konfiguracji"
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Kacper Herchel <kacperski1@gmail.com>, 2017\n"
|
||||
"Language-Team: Polish (Poland) (https://www.transifex.com/solus-project/teams/68407/pl_PL/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pl_PL\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integracja Linuksa ze Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Zarządzaj zachowaniem klienta Steam i gier. Ustawienia dadzą efekt dopiero "
|
||||
"po zrestartowaniu klienta Steam. Użyj opcji „Opuść Steam” aby upewnić się, "
|
||||
"że klient został zamknięty."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Używaj natywnego środowiska"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr ""
|
||||
"Przełączaj się między natywnym środowiskiem uruchomieniowym i wersją "
|
||||
"dołączaną do klienta Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Ta opcja została zablokowana, ponieważ używany system jest 32-bitowy"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"To może naprawić działanie niektórych gier, ale wyłączy możliwość "
|
||||
"przeglądania sklepu Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Wymuś tryb 32-bitowy dla Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Używaj biblioteki przechwytującej"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Wymusza na grach Steam używanie większej ilości natywnych bibliotek, co "
|
||||
"zwiększa kompatybilność."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Używaj biblioteki przekierowującej"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Nadpisuje wywołania systemowe, aby poprawić błędy w niektórych linuksowych "
|
||||
"portach."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Nie udało się zapisać konfiguracji"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Marcelo Ferreira <marceloffdeoliveira@gmail.com>, 2017\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/solus-project/teams/68407/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integração Steam® com Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla o comportamento dos jogos e do programa da Steam. As configurações "
|
||||
"não terão efeito até que o programa seja reiniciado. Utilize a opção \"Sair "
|
||||
"da Steam\" para garantir que ele seja fechado."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar runtime nativo"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Alternar entre o runtime nativo e o incluso da Steam."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Esta opção foi desativada, uma vez que o sistema já é de 32-bits"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Isto pode funcionar em alguns jogos defeituosos, mas irá desativar o "
|
||||
"navegador da loja da Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forçar modo 32-bits para a Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Usar a biblioteca de interceptação"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Forçar aplicativos da Steam a usar mais bibliotecas nativas para maximizar a"
|
||||
" compatibilidade."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Usar a biblioteca de redirecionamento"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Sobrescrever chamadas do sistema para corrigir bugs conhecidos em algumas "
|
||||
"adaptações para Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Falha ao salvar configuração"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Christophe Silva <christophesilva80@gmail.com>, 2017\n"
|
||||
"Language-Team: Portuguese (Portugal) (https://www.transifex.com/solus-project/teams/68407/pt_PT/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_PT\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integração Linux Steam®"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controla o comportamento do cliente e jogos em Steam. As configurações não "
|
||||
"terão efeito antes de o Cliente de Steam ser reinicializado. Use a opção "
|
||||
"\"Sair do Steam\" para ter a certeza que o cliente fecha."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Usar \"runtime\" nativo"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Alternar entre o \"runtime\" nativo e o \"runtime\" Steam incluído."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Esta opção foi desativada, já que o sistema já possui 32 bits"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Isto pode resolver alguns jogos danificados, mas irá desativar o navegador "
|
||||
"da loja Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forçar o modo de 32 bits para Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Use a biblioteca de intercetação"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Força aplicativos do Steam para usar mais bibliotecas nativas para maximizar"
|
||||
" a compatibilidade."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Use a biblioteca de redirecionamento"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Substitua as chamadas do sistema para corrigir erros conhecidos em algumas "
|
||||
"portas Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Falha ao salvar a configuração"
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Andrei B <snoozeisdoze@gmail.com>, 2017\n"
|
||||
"Language-Team: Romanian (Romania) (https://www.transifex.com/solus-project/teams/68407/ro_RO/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ro_RO\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Integrare Steam® Linux"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Controleaza comportamentul jocurilor si al clientului Steam. Setarile nu vor"
|
||||
" avea efect pana cand Clientul Steam nu este restartat. Utilizati optiunea "
|
||||
"\"Exit Steam\" pentru a va asigura ca se inchide."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Utilizati runtime-ul nativ"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Comuta intre runtime-ul nativ si cel inclus in Steam"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Aceasta optiune a fost dezactivata deoarece sistemul este deja 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Aceasta poate fi o solutie pentru unele jocuri nefunctionale, dar va "
|
||||
"dezactiva navigatorul magazinul Steam."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Forteaza modul 32-bit pentru Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Utilizati libraria de interceptare"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Fortati aplicatiile Steam sa foloseasca mai multe librarii native pentru a "
|
||||
"maximiza compatibilitatea."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Utilizati libraria de redirectionare"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr ""
|
||||
"Suprascrie apelurile de sistem pentru a repara erori cunoscute in unele "
|
||||
"portari Linux."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Nu s-a reusit salvarea configuratiei"
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Puppelimies <max.haureus@gmail.com>, 2017\n"
|
||||
"Language-Team: Swedish (Sweden) (https://www.transifex.com/solus-project/teams/68407/sv_SE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: sv_SE\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Linux Steam® Integration"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr ""
|
||||
"Styr beteendet av Steam klienten och spel. Inställningarna kommer inte att "
|
||||
"träda i kraft förrän Steam klienten startas om. Använd 'Avsluta Steam' "
|
||||
"alternativet för att se till att den stängs."
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "Använd inbyggd runtime"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "Växla mellan inbyggd runtime och inkluderad Steam runtime."
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "Detta alternativ är inaktiverat eftersom systemet redan är 32-bit"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr ""
|
||||
"Detta kan lösa endel trasiga spel, men inaktiverar Steam butik bläddraren."
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "Tvinga 32-bit läge för Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "Använd avledningsbiblioteket"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr ""
|
||||
"Tvinga Steam applikationer att använda fler inbyggda bibliotek för att "
|
||||
"maximera kompatibilitet."
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "Använd omdirigeringsbiblioteket"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "Åsidosätt systemanrop för att åtgärda kända fel i vissa Linux-portar."
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "Spara konfiguration misslyckades"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
tx pull -a --minimum-perc=100
|
||||
|
||||
cd po
|
||||
rm LINGUAS
|
||||
|
||||
for i in *.po ; do
|
||||
echo `echo $i|sed 's/.po$//'` >> LINGUAS
|
||||
done
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the linux-steam-integration package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: linux-steam-integration\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-11-05 19:28+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: plantman <weihanlin@live.com>, 2017\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/solus-project/teams/68407/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. Sort out window bits
|
||||
#. header label
|
||||
#: src/frontend/main-window.c:131 src/frontend/main-window.c:148
|
||||
msgid "Linux Steam® Integration"
|
||||
msgstr "Steam® 的 Linux 系统整合"
|
||||
|
||||
#: src/frontend/main-window.c:162
|
||||
msgid ""
|
||||
"Control the behaviour of the Steam client and games. Settings will not take "
|
||||
"effect until the Steam Client is restarted. Use the 'Exit Steam' option to "
|
||||
"ensure it closes."
|
||||
msgstr "控制 Steam 客户端和游戏的运行方式。配置在重启后生效。使用“退出 Steam”选项来确保完全退出。"
|
||||
|
||||
#: src/frontend/main-window.c:191
|
||||
msgid "Use native runtime"
|
||||
msgstr "使用系统运行时"
|
||||
|
||||
#: src/frontend/main-window.c:192
|
||||
msgid "Switch between the native runtime and the bundled Steam runtime."
|
||||
msgstr "在系统运行时跟 Steam 自带运行时之间切换"
|
||||
|
||||
#. Label is shown to indicate we can't enable 32-bit option
|
||||
#: src/frontend/main-window.c:201
|
||||
msgid "This option has been disabled as the system is already 32-bit"
|
||||
msgstr "此选项已禁用,因为系统已经是 32 位了"
|
||||
|
||||
#: src/frontend/main-window.c:205
|
||||
msgid ""
|
||||
"This may workaround some broken games, but will disable the Steam store "
|
||||
"browser."
|
||||
msgstr "这个解决方法可能会修复某些运行不正常的游戏,但是会禁用 Steam 商店浏览器"
|
||||
|
||||
#: src/frontend/main-window.c:210
|
||||
msgid "Force 32-bit mode for Steam"
|
||||
msgstr "强制以 32 位模式运行 Steam"
|
||||
|
||||
#: src/frontend/main-window.c:218
|
||||
msgid "Use the intercept library"
|
||||
msgstr "使用 “Intercept” 库"
|
||||
|
||||
#: src/frontend/main-window.c:219
|
||||
msgid ""
|
||||
"Force Steam applications to use more native libraries to maximise "
|
||||
"compatibility."
|
||||
msgstr "强制让 Steam 尽可能使用系统自带库,以确保最好的兼容性"
|
||||
|
||||
#: src/frontend/main-window.c:228
|
||||
msgid "Use the redirect library"
|
||||
msgstr "使用 \"Redirect\" 库"
|
||||
|
||||
#: src/frontend/main-window.c:229
|
||||
msgid "Override system calls to fix known bugs in some Linux ports."
|
||||
msgstr "覆盖系统调用以修复某些已知的游戏运行问题"
|
||||
|
||||
#: src/frontend/main-window.c:383
|
||||
msgid "Failed to save configuration"
|
||||
msgstr "无法保存配置"
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* Mark a variable/argument as unused to skip warnings */
|
||||
#define __lsi_unused__ __attribute__((unused))
|
||||
|
||||
/* Force inlining of a function */
|
||||
#define __lsi_inline__ __attribute__((always_inline))
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "files.h"
|
||||
#include "log.h"
|
||||
#include "nica/array.h"
|
||||
#include "nica/util.h"
|
||||
#include "vdf.h"
|
||||
|
||||
DEF_AUTOFREE(VdfFile, vdf_file_close)
|
||||
|
||||
bool lsi_file_exists(const char *path)
|
||||
{
|
||||
__lsi_unused__ struct stat st = { 0 };
|
||||
return lstat(path, &st) == 0;
|
||||
}
|
||||
|
||||
const char *lsi_get_home_dir()
|
||||
{
|
||||
char *c = NULL;
|
||||
struct passwd *p = NULL;
|
||||
|
||||
c = getenv("HOME");
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
p = getpwuid(getuid());
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
return p->pw_dir;
|
||||
}
|
||||
|
||||
char *lsi_get_user_config_dir()
|
||||
{
|
||||
const char *home = lsi_get_home_dir();
|
||||
char *c = NULL;
|
||||
if (asprintf(&c, "%s/.config", home) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just use .local/share/Steam at this point..
|
||||
*/
|
||||
static inline char *lsi_get_fallback_steam_dir(const char *home)
|
||||
{
|
||||
char *p = NULL;
|
||||
if (asprintf(&p, "%s/.local/share/Steam", home) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *lsi_get_steam_dir()
|
||||
{
|
||||
const char *homedir = NULL;
|
||||
autofree(char) *candidate = NULL;
|
||||
autofree(char) *resolv = NULL;
|
||||
|
||||
homedir = lsi_get_home_dir();
|
||||
if (asprintf(&candidate, "%s/.steam/root", homedir) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resolv = realpath(candidate, NULL);
|
||||
if (!resolv || !lsi_file_exists(resolv)) {
|
||||
return lsi_get_fallback_steam_dir(homedir);
|
||||
}
|
||||
return strdup(resolv);
|
||||
}
|
||||
|
||||
char *lsi_get_process_name(void)
|
||||
{
|
||||
char *realp = NULL;
|
||||
|
||||
realp = realpath("/proc/self/exe", NULL);
|
||||
if (!realp) {
|
||||
return NULL;
|
||||
}
|
||||
return realp;
|
||||
}
|
||||
|
||||
char *lsi_get_process_base_name(void)
|
||||
{
|
||||
autofree(char) *p = NULL;
|
||||
char *basep = NULL;
|
||||
|
||||
p = lsi_get_process_name();
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
basep = basename(p);
|
||||
return strdup(basep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if a string is numeric..
|
||||
*/
|
||||
static inline bool lsi_is_string_numeric(char *p)
|
||||
{
|
||||
char *s;
|
||||
|
||||
for (s = p; *s; s++) {
|
||||
if (!isdigit(*s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't wind, empty string */
|
||||
if (s == p) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char **lsi_get_steam_paths(void)
|
||||
{
|
||||
autofree(char) *steam_root = NULL;
|
||||
autofree(char) *lib_conf = NULL;
|
||||
autofree(VdfFile) *vdf = NULL;
|
||||
VdfNode *root = NULL;
|
||||
VdfNode *node = NULL;
|
||||
NcArray *array = NULL;
|
||||
|
||||
steam_root = lsi_get_steam_dir();
|
||||
if (!steam_root) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array = nc_array_new();
|
||||
if (!nc_array_add(array, strdup(steam_root))) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (asprintf(&lib_conf, "%s/steamapps/libraryfolders.vdf", steam_root) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdf = vdf_file_open(lib_conf);
|
||||
if (!vdf) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
if (!vdf_file_parse(vdf)) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Look up LibraryFolders under root */
|
||||
root = vdf_file_get_root(vdf);
|
||||
node = vdf_node_get(root, "LibraryFolders", NULL);
|
||||
if (!node) {
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Walk all nodes immediately within LibraryFolders and ignore sections */
|
||||
for (VdfNode *n = node->child; n; n = n->sibling) {
|
||||
if (!n->value) {
|
||||
continue;
|
||||
}
|
||||
if (lsi_is_string_numeric(n->key)) {
|
||||
if (!nc_array_add(array, strdup(n->value))) {
|
||||
goto bail;
|
||||
}
|
||||
lsi_log_debug("vdf: discovered LibraryFolders: %s", n->value);
|
||||
}
|
||||
}
|
||||
|
||||
fallback:
|
||||
/* Trick nica into storing empty value to so we can terminate the array */
|
||||
if (!nc_array_add(array, (void *)(long)1)) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Steal the blob straight out of the array */
|
||||
char **data = (char **)array->data;
|
||||
data[array->len - 1] = NULL;
|
||||
free(array);
|
||||
return data;
|
||||
|
||||
bail:
|
||||
nc_array_free(&array, free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Determine the home directory
|
||||
*/
|
||||
const char *lsi_get_home_dir(void);
|
||||
|
||||
/**
|
||||
* Determine the home config directory
|
||||
*/
|
||||
char *lsi_get_user_config_dir(void);
|
||||
|
||||
/**
|
||||
* Find out where Steam is installed
|
||||
*/
|
||||
char *lsi_get_steam_dir(void);
|
||||
|
||||
/**
|
||||
* Grab all the valid steam installation directories
|
||||
*/
|
||||
char **lsi_get_steam_paths(void);
|
||||
|
||||
/**
|
||||
* Quick helper to determine if the path exists
|
||||
*/
|
||||
bool lsi_file_exists(const char *path);
|
||||
|
||||
/**
|
||||
* Return the full process name
|
||||
*/
|
||||
char *lsi_get_process_name(void);
|
||||
|
||||
/**
|
||||
* Determine the basename'd process
|
||||
*/
|
||||
char *lsi_get_process_base_name(void);
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "nica/util.h"
|
||||
|
||||
static const char *_log_id = "__init__";
|
||||
|
||||
void lsi_log_set_id(const char *id)
|
||||
{
|
||||
_log_id = id;
|
||||
}
|
||||
|
||||
void lsi_log_debug(const char *format, ...)
|
||||
{
|
||||
if (!getenv("LSI_DEBUG")) {
|
||||
return;
|
||||
}
|
||||
|
||||
autofree(char) *p = NULL;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
if (!vasprintf(&p, format, va)) {
|
||||
/* At least print *something */
|
||||
fprintf(stderr, "%s\n", format);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\033[32;1m[lsi:%s]\033[0m %s\n", _log_id, p);
|
||||
|
||||
end:
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void lsi_log_info(const char *format, ...)
|
||||
{
|
||||
autofree(char) *p = NULL;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
if (!vasprintf(&p, format, va)) {
|
||||
/* At least print *something */
|
||||
fprintf(stderr, "%s\n", format);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\033[34;1m[lsi:%s]\033[0m %s\n", _log_id, p);
|
||||
|
||||
end:
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void lsi_log_warn(const char *format, ...)
|
||||
{
|
||||
autofree(char) *p = NULL;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
if (!vasprintf(&p, format, va)) {
|
||||
/* At least print *something */
|
||||
fprintf(stderr, "%s\n", format);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\033[33;1m[lsi:%s]\033[0m %s\n", _log_id, p);
|
||||
|
||||
end:
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void lsi_log_error(const char *format, ...)
|
||||
{
|
||||
autofree(char) *p = NULL;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
if (!vasprintf(&p, format, va)) {
|
||||
/* At least print *something */
|
||||
fprintf(stderr, "%s\n", format);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\033[31;1m[lsi:%s]\033[0m %s\n", _log_id, p);
|
||||
|
||||
end:
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Set the ID used in all log output
|
||||
*/
|
||||
void lsi_log_set_id(const char *id);
|
||||
|
||||
/**
|
||||
* Emit some debug information if LSI_DEBUG is set
|
||||
*/
|
||||
void lsi_log_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/**
|
||||
* Emit information, always shown
|
||||
*/
|
||||
void lsi_log_info(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/**
|
||||
* Emit a warning, always shown
|
||||
*/
|
||||
void lsi_log_warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/**
|
||||
* Emit an error, always shown
|
||||
*/
|
||||
void lsi_log_error(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,19 @@
|
||||
# Build the common library to share functionality between various components
|
||||
|
||||
lsi_common_sources = [
|
||||
'files.c',
|
||||
'log.c',
|
||||
'vdf.c',
|
||||
]
|
||||
|
||||
lib_lsi_common = static_library(
|
||||
'lsi-lsi-common',
|
||||
sources: lsi_common_sources + nica_sources,
|
||||
c_args: ['-fvisibility=hidden'],
|
||||
include_directories: nica_includes,
|
||||
)
|
||||
|
||||
link_lsi_common = declare_dependency(
|
||||
link_with: lib_lsi_common,
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
@@ -0,0 +1,705 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "vdf.h"
|
||||
|
||||
#define VDF_CHAR_QUOTE '"'
|
||||
#define VDF_CHAR_SLASH '\\'
|
||||
#define VDF_CHAR_OPEN '{'
|
||||
#define VDF_CHAR_CLOSE '}'
|
||||
|
||||
typedef enum {
|
||||
VDF_FLAG_MIN = 1 << 0,
|
||||
VDF_FLAG_QUOTED = 1 << 1, /**< Inside a quoted block */
|
||||
VDF_FLAG_COMMENT = 1 << 2, /**< Inside a comment block */
|
||||
VDF_FLAG_BLOCK_COMMENT = 1 << 3, /**< Inside a multiline comment block */
|
||||
VDF_FLAG_CHEW_WHITESPACE = 1 << 4,
|
||||
} VdfFlags;
|
||||
|
||||
/**
|
||||
* VdfFile is the main dude required for parsing a file
|
||||
*/
|
||||
struct VdfFile {
|
||||
/* Input */
|
||||
size_t buffer_len;
|
||||
char *buffer;
|
||||
|
||||
/* Output (memstream) */
|
||||
FILE *ring;
|
||||
char *out_buffer;
|
||||
size_t out_len;
|
||||
|
||||
/* Input file */
|
||||
int fd;
|
||||
|
||||
/* Tracking */
|
||||
size_t index;
|
||||
int flags;
|
||||
char *key_id;
|
||||
int n_quote; /**only allow 2 sets per "line" */
|
||||
VdfNode *section;
|
||||
VdfNode *root;
|
||||
|
||||
bool error; /**< Allow breaking. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Function pointer to the generic handler functions.
|
||||
*/
|
||||
typedef bool (*vdf_handle_func)(VdfFile *file, char c);
|
||||
|
||||
/**
|
||||
* Free node
|
||||
*/
|
||||
static void vdf_node_free(VdfNode *node)
|
||||
{
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
if (node->key) {
|
||||
free(node->key);
|
||||
}
|
||||
if (node->value) {
|
||||
free(node->value);
|
||||
}
|
||||
|
||||
vdf_node_free(node->sibling);
|
||||
vdf_node_free(node->child);
|
||||
free(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new VdfNode, copying the key and value if they exist.
|
||||
*/
|
||||
static VdfNode *vdf_node_new(const char *key, const char *value)
|
||||
{
|
||||
VdfNode *ret = NULL;
|
||||
|
||||
ret = calloc(1, sizeof(VdfNode));
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
if (key) {
|
||||
ret->key = strdup(key);
|
||||
if (!ret->key) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
if (value) {
|
||||
ret->value = strdup(value);
|
||||
if (!ret->value) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
failed:
|
||||
vdf_node_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vdf_file_close(VdfFile *file)
|
||||
{
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file->buffer) {
|
||||
munmap(file->buffer, file->buffer_len);
|
||||
}
|
||||
if (file->fd > -1) {
|
||||
close(file->fd);
|
||||
}
|
||||
if (file->ring) {
|
||||
fclose(file->ring);
|
||||
}
|
||||
if (file->out_buffer) {
|
||||
free(file->out_buffer);
|
||||
}
|
||||
if (file->key_id) {
|
||||
free(file->key_id);
|
||||
}
|
||||
/* TODO: Make free separate from close, so we can just keep the node */
|
||||
vdf_node_free(file->root);
|
||||
free(file);
|
||||
}
|
||||
|
||||
VdfFile *vdf_file_open(const char *path)
|
||||
{
|
||||
VdfFile *ret = NULL;
|
||||
struct stat st = { 0 };
|
||||
|
||||
ret = calloc(1, sizeof(VdfFile));
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
ret->fd = -1;
|
||||
|
||||
ret->fd = open(path, O_RDONLY);
|
||||
if (ret->fd < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fstat(ret->fd, &st) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret->buffer_len = (size_t)st.st_size;
|
||||
|
||||
ret->buffer = mmap(NULL, ret->buffer_len, PROT_READ, MAP_PRIVATE, ret->fd, 0);
|
||||
if (!ret->buffer) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Now we have input map, build output memstream */
|
||||
ret->ring = open_memstream(&ret->out_buffer, &ret->out_len);
|
||||
if (!ret->ring) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ret;
|
||||
fail:
|
||||
vdf_file_close(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VdfNode *vdf_file_get_root(VdfFile *file)
|
||||
{
|
||||
if (!file) {
|
||||
return NULL;
|
||||
}
|
||||
return file->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the buffer pointer forward if possible.
|
||||
*/
|
||||
static char vdf_file_next(VdfFile *file)
|
||||
{
|
||||
file->index++;
|
||||
if (file->index > file->buffer_len) {
|
||||
file->index = file->buffer_len;
|
||||
return '\0';
|
||||
}
|
||||
return file->buffer[file->index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to peek at the next character in the buffer
|
||||
*/
|
||||
static char vdf_file_peek(VdfFile *file)
|
||||
{
|
||||
if (file->index + 1 > file->buffer_len) {
|
||||
return '\0';
|
||||
}
|
||||
return file->buffer[file->index + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip a character in the stream
|
||||
*/
|
||||
static void vdf_file_skip(VdfFile *file)
|
||||
{
|
||||
if (++file->index > file->buffer_len) {
|
||||
file->index = file->buffer_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a char to the ring buffer
|
||||
*/
|
||||
static bool vdf_file_push_ring(VdfFile *file, char c)
|
||||
{
|
||||
if (fwrite(&c, 1, sizeof(c), file->ring) != 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* End the ring buffer by writing a NUL byte
|
||||
*/
|
||||
static bool vdf_file_end_ring(VdfFile *file)
|
||||
{
|
||||
if (!vdf_file_push_ring(file, '\0')) {
|
||||
return false;
|
||||
}
|
||||
if (fflush(file->ring) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the ring once more to begin writing again.
|
||||
*/
|
||||
static bool vdf_file_reset_ring(VdfFile *file)
|
||||
{
|
||||
if (fflush(file->ring) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fseek(file->ring, 0, SEEK_SET) != 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle newlines
|
||||
*
|
||||
* When encountering a newline we need to do a bit of state cleanup
|
||||
*/
|
||||
static bool vdf_file_handle_newline(VdfFile *file, char c)
|
||||
{
|
||||
if (c != '\n') {
|
||||
return false;
|
||||
}
|
||||
file->flags &= ~VDF_FLAG_COMMENT;
|
||||
if (file->flags & VDF_FLAG_QUOTED) {
|
||||
file->flags |= VDF_FLAG_CHEW_WHITESPACE;
|
||||
} else {
|
||||
file->flags &= ~VDF_FLAG_CHEW_WHITESPACE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle quote characters
|
||||
*
|
||||
* This function deals with the start/end quotes encountered in the stream
|
||||
* to set keys and values
|
||||
*/
|
||||
static bool vdf_file_handle_quote(VdfFile *file, char c)
|
||||
{
|
||||
if (c != VDF_CHAR_QUOTE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Start tracking quoting if necessary */
|
||||
if (!(file->flags & VDF_FLAG_QUOTED)) {
|
||||
/* Start tracking the quoted thing */
|
||||
if (file->n_quote > 2) {
|
||||
lsi_log_error("vdf: Cannot start a third section");
|
||||
goto bail;
|
||||
}
|
||||
file->flags |= VDF_FLAG_QUOTED;
|
||||
file->flags &= ~VDF_FLAG_CHEW_WHITESPACE;
|
||||
vdf_file_reset_ring(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
++file->n_quote;
|
||||
|
||||
/* Stop tracking the quoted thing */
|
||||
file->flags ^= VDF_FLAG_QUOTED;
|
||||
vdf_file_end_ring(file);
|
||||
|
||||
/* Capture the ID */
|
||||
if (file->n_quote == 1) {
|
||||
if (file->key_id) {
|
||||
lsi_log_error("vdf: Key should not already be set!");
|
||||
goto bail;
|
||||
}
|
||||
file->key_id = strdup(file->out_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!file->key_id) {
|
||||
lsi_log_error("vdf: Missing key for value!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (file->n_quote != 2) {
|
||||
lsi_log_error("vdf: Invalid number of quotes on line");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Reset n_quote now */
|
||||
file->n_quote = 0;
|
||||
|
||||
/* Store the node now */
|
||||
VdfNode *t = vdf_node_new(file->key_id, file->out_buffer);
|
||||
if (!t) {
|
||||
fputs("OOM\n", stderr);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* dispose of key ID now */
|
||||
free(file->key_id);
|
||||
file->key_id = NULL;
|
||||
file->flags &= ~VDF_FLAG_CHEW_WHITESPACE;
|
||||
|
||||
/* Store the new key->value mapping */
|
||||
t->parent = file->section->parent;
|
||||
t->sibling = file->section->child;
|
||||
file->section->child = t;
|
||||
|
||||
return true;
|
||||
|
||||
bail:
|
||||
file->error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle opening of a section
|
||||
*
|
||||
* This will perform some basic validation, and when all conditions are satisfied
|
||||
* we'll attempt construction of a new section
|
||||
*/
|
||||
static bool vdf_file_handle_section_open(VdfFile *file)
|
||||
{
|
||||
VdfNode *node = NULL;
|
||||
vdf_file_reset_ring(file);
|
||||
|
||||
if (file->n_quote == 2) {
|
||||
lsi_log_error("vdf: section cannot have value!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (file->n_quote != 1) {
|
||||
lsi_log_error("vdf: Section is missing id!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
file->n_quote = 0;
|
||||
|
||||
if (!file->key_id) {
|
||||
lsi_log_error("vdf: key_id should not be NULL!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
node = vdf_node_new(file->out_buffer, NULL);
|
||||
if (!node) {
|
||||
goto bail;
|
||||
}
|
||||
free(file->key_id);
|
||||
file->key_id = NULL;
|
||||
|
||||
node->parent = file->section;
|
||||
node->sibling = file->section->child;
|
||||
file->section->child = node;
|
||||
|
||||
file->section = node;
|
||||
return true;
|
||||
|
||||
bail:
|
||||
file->error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle closing of a section
|
||||
*
|
||||
* This will perform some basic error checking to ensure we're closing it
|
||||
* correctly. At this point we'll wind back to the nodes parent
|
||||
*/
|
||||
static bool vdf_file_handle_section_close(VdfFile *file)
|
||||
{
|
||||
if (file->n_quote != 0) {
|
||||
lsi_log_error("vdf: unterminated section!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!file->section) {
|
||||
lsi_log_error("vdf: Closed section without creating one!");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Wind back */
|
||||
file->section = file->section->parent;
|
||||
if (!file->section) {
|
||||
goto bail;
|
||||
}
|
||||
return true;
|
||||
|
||||
bail:
|
||||
file->error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle brace characters
|
||||
*
|
||||
* This function will proxy to the relevant handler function
|
||||
*/
|
||||
static bool vdf_file_handle_section(VdfFile *file, char c)
|
||||
{
|
||||
switch (c) {
|
||||
case VDF_CHAR_CLOSE:
|
||||
return vdf_file_handle_section_close(file);
|
||||
case VDF_CHAR_OPEN:
|
||||
return vdf_file_handle_section_open(file);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle normal text
|
||||
*
|
||||
* Whilst in QUOTED mode we'll keep pushing text to the buffer, which will
|
||||
* later become keys and values.
|
||||
*
|
||||
* We'll also do some sanity checks here to escape any common text sequences,
|
||||
* so as not to break the quotes
|
||||
*/
|
||||
static bool vdf_file_handle_text(VdfFile *file, char c)
|
||||
{
|
||||
char next = '\0';
|
||||
|
||||
/* Must be within quoting */
|
||||
if (!(file->flags & VDF_FLAG_QUOTED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file->flags & VDF_FLAG_CHEW_WHITESPACE && isspace(c)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
file->flags &= ~VDF_FLAG_CHEW_WHITESPACE;
|
||||
|
||||
/* Check if we need to do any escaping */
|
||||
if (c != VDF_CHAR_SLASH) {
|
||||
vdf_file_push_ring(file, c);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform text escaping */
|
||||
switch ((next = vdf_file_peek(file))) {
|
||||
case 'r':
|
||||
vdf_file_push_ring(file, '\r');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
case 'n':
|
||||
vdf_file_push_ring(file, '\n');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
case 't':
|
||||
vdf_file_push_ring(file, '\t');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
case '"':
|
||||
vdf_file_push_ring(file, '"');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
case '\'':
|
||||
vdf_file_push_ring(file, '\'');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
case '\\':
|
||||
vdf_file_push_ring(file, '\\');
|
||||
vdf_file_skip(file);
|
||||
return true;
|
||||
default:
|
||||
// TODO: Handle errors properly!
|
||||
lsi_log_error("vdf: Invalid escape sequence '\\%c'", next);
|
||||
file->error = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle multiline comments
|
||||
*
|
||||
* This method will attempt to look for the start and ends of multiline comment
|
||||
* blocks, which will result in all text from the start until the trailing
|
||||
* characters of the comment to be ignored.
|
||||
*/
|
||||
static bool vdf_file_handle_multiline_comment(VdfFile *file, char c)
|
||||
{
|
||||
if (c == '/' && vdf_file_peek(file) == '*') {
|
||||
vdf_file_skip(file);
|
||||
if (file->flags & VDF_FLAG_BLOCK_COMMENT) {
|
||||
lsi_log_error("vdf: Starting nested block comment");
|
||||
goto bail;
|
||||
}
|
||||
file->flags |= VDF_FLAG_BLOCK_COMMENT;
|
||||
} else if (c == '*' && vdf_file_peek(file) == '/') {
|
||||
vdf_file_skip(file);
|
||||
if (!(file->flags & VDF_FLAG_BLOCK_COMMENT)) {
|
||||
lsi_log_error("vdf: Ended comment without starting one");
|
||||
goto bail;
|
||||
}
|
||||
file->flags ^= VDF_FLAG_BLOCK_COMMENT;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
bail:
|
||||
file->error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle single comments
|
||||
*
|
||||
* This will handle C++ style '//' comments and cause the remaining text on
|
||||
* the line to be ignored
|
||||
*/
|
||||
static bool vdf_file_handle_single_comment(VdfFile *file, char c)
|
||||
{
|
||||
/* Don't switch us on if we're inside a multiline comment! */
|
||||
if (file->flags & VDF_FLAG_BLOCK_COMMENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Must be a C++ style comment. */
|
||||
if (!(c == '/' && vdf_file_peek(file) == '/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip the next character, and turn on comment mode */
|
||||
vdf_file_skip(file);
|
||||
file->flags |= VDF_FLAG_COMMENT;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle comment state
|
||||
*
|
||||
* If we're in a comment we might need to skip this line entirely, however
|
||||
* if its a multiline comment we need to preemptively evaluate the termination.
|
||||
*/
|
||||
static bool vdf_file_handle_commented(VdfFile *file, char c)
|
||||
{
|
||||
if (file->flags & VDF_FLAG_COMMENT) {
|
||||
return true;
|
||||
}
|
||||
if (file->flags & VDF_FLAG_BLOCK_COMMENT) {
|
||||
/* Always return true here, must ignore the line! */
|
||||
vdf_file_handle_multiline_comment(file, c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vdf_file_parse(VdfFile *file)
|
||||
{
|
||||
char c = file->buffer[0];
|
||||
bool ret = false;
|
||||
static vdf_handle_func funcs[] = {
|
||||
&vdf_file_handle_newline,
|
||||
&vdf_file_handle_commented,
|
||||
&vdf_file_handle_quote,
|
||||
&vdf_file_handle_text,
|
||||
&vdf_file_handle_section,
|
||||
&vdf_file_handle_single_comment,
|
||||
&vdf_file_handle_multiline_comment,
|
||||
};
|
||||
static size_t n_funcs = sizeof(funcs) / sizeof(funcs[0]);
|
||||
|
||||
file->flags = 0;
|
||||
file->key_id = NULL;
|
||||
file->section = file->root = vdf_node_new(NULL, NULL);
|
||||
if (!file->root) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
while (c != '\0') {
|
||||
/* Pass through all of our functions */
|
||||
for (size_t i = 0; i < n_funcs; i++) {
|
||||
if (funcs[i](file, c)) {
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
if (file->error) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Now the only thing left is to allow whitespace */
|
||||
if (!isspace(c)) {
|
||||
lsi_log_error("vdf: Illegal character in stream: '%c'", c);
|
||||
goto bail;
|
||||
}
|
||||
next:
|
||||
c = vdf_file_next(file);
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
/* Check a comment actually ended .. */
|
||||
if (file->flags & VDF_FLAG_BLOCK_COMMENT) {
|
||||
lsi_log_error("vdf: Started block comment without ending one");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
bail:
|
||||
if (file->key_id) {
|
||||
free(file->key_id);
|
||||
file->key_id = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
VdfNode *vdf_node_get_child(VdfNode *node, const char *id)
|
||||
{
|
||||
if (!id || !node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (VdfNode *tmp = node->child; tmp; tmp = tmp->sibling) {
|
||||
if (tmp->key && strcmp(tmp->key, id) == 0) {
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VdfNode *vdf_node_get(VdfNode *node, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, node);
|
||||
char *id = NULL;
|
||||
VdfNode *retr = node;
|
||||
|
||||
while ((id = va_arg(va, char *)) != NULL) {
|
||||
retr = vdf_node_get_child(retr, id);
|
||||
if (!retr) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
va_end(va);
|
||||
return retr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/**
|
||||
* VdfFile is an opaque type containing fields used primarily for parsing
|
||||
* a .vdf file
|
||||
*
|
||||
* A VdfFile is used to parse the Valve Data Format file, allowing LSI to
|
||||
* parse the users library paths, etc.
|
||||
*/
|
||||
typedef struct VdfFile VdfFile;
|
||||
|
||||
/**
|
||||
* A VdfNode may be any element in a VDF document, and has optional value,
|
||||
* children and parent.
|
||||
* The root node in a document has no parent
|
||||
*/
|
||||
typedef struct VdfNode {
|
||||
struct VdfNode *sibling; /**First sibling */
|
||||
struct VdfNode *child; /**<First child, may have siblings. */
|
||||
struct VdfNode *parent; /**<Parent if not the root */
|
||||
|
||||
char *key; /**<Only null for the root node */
|
||||
char *value; /**<Only exists for key-value nodes */
|
||||
} VdfNode;
|
||||
|
||||
/**
|
||||
* Close and free an existing VdfFile
|
||||
*/
|
||||
void vdf_file_close(VdfFile *file);
|
||||
|
||||
/**
|
||||
* Attempt to map the source path and open a .vdf file
|
||||
*/
|
||||
VdfFile *vdf_file_open(const char *path);
|
||||
|
||||
/**
|
||||
* Return the root node for this file, if it has been parsed
|
||||
*/
|
||||
VdfNode *vdf_file_get_root(VdfFile *file);
|
||||
|
||||
/**
|
||||
* Attempt to parse a file
|
||||
*
|
||||
* @file Pointer to a VdfFile instance
|
||||
* @returns true if parsing succeeds
|
||||
*/
|
||||
bool vdf_file_parse(VdfFile *file);
|
||||
|
||||
/**
|
||||
* Grab a child node by the given ID
|
||||
*
|
||||
* @node Parent node
|
||||
* @id Child ID
|
||||
*/
|
||||
VdfNode *vdf_node_get_child(VdfNode *node, const char *id);
|
||||
|
||||
/**
|
||||
* Variadic function to retrieve a child node
|
||||
*
|
||||
* This function will keep iterating the args passed until it hits NULL and
|
||||
* has a node, or no node can be found prior to this and it returns NULL.
|
||||
*/
|
||||
__attribute__((sentinel(0))) VdfNode *vdf_node_get(VdfNode *node, ...);
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "main-window.h"
|
||||
#include "config.h"
|
||||
#include "lsi.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct _LsiSettingsWindow {
|
||||
GtkWindow parent;
|
||||
LsiConfig config; /**<Current LSI config */
|
||||
|
||||
/* Only when libintercept is enabled will we have this option */
|
||||
#ifdef HAVE_LIBINTERCEPT
|
||||
GtkWidget *check_intercept;
|
||||
#endif
|
||||
|
||||
/* Only when libredirect is enabled will we have this option */
|
||||
#ifdef HAVE_LIBREDIRECT
|
||||
GtkWidget *check_redirect;
|
||||
#endif
|
||||
|
||||
/* Always have these guys */
|
||||
GtkWidget *check_native;
|
||||
GtkWidget *check_emul32;
|
||||
};
|
||||
|
||||
struct _LsiSettingsWindowClass {
|
||||
GtkWindowClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(LsiSettingsWindow, lsi_settings_window, GTK_TYPE_WINDOW)
|
||||
|
||||
static void _align_label(GtkWidget *label);
|
||||
static void insert_grid(GtkWidget *grid, int *row, const char *title, const char *description,
|
||||
GtkWidget *widget);
|
||||
static GtkWidget *insert_grid_toggle(GtkWidget *grid, int *row, const char *title,
|
||||
const char *description);
|
||||
static void set_row_sensitive(GtkWidget *toggle, gboolean sensitive);
|
||||
static void lsi_native_swapped(LsiSettingsWindow *window, gpointer v);
|
||||
static gboolean lsi_window_closed(LsiSettingsWindow *window, GdkEvent *event, gpointer v);
|
||||
|
||||
/**
|
||||
* lsi_settings_window_new:
|
||||
*
|
||||
* Construct a new LsiSettingsWindow object
|
||||
*/
|
||||
GtkWidget *lsi_settings_window_new()
|
||||
{
|
||||
return g_object_new(LSI_TYPE_SETTINGS_WINDOW, "type", GTK_WINDOW_TOPLEVEL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_settings_window_dispose:
|
||||
*
|
||||
* Clean up a LsiSettingsWindow instance
|
||||
*/
|
||||
static void lsi_settings_window_dispose(GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS(lsi_settings_window_parent_class)->dispose(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_settings_window_class_init:
|
||||
*
|
||||
* Handle class initialisation
|
||||
*/
|
||||
static void lsi_settings_window_class_init(LsiSettingsWindowClass *klazz)
|
||||
{
|
||||
GObjectClass *obj_class = G_OBJECT_CLASS(klazz);
|
||||
|
||||
/* gobject vtable hookup */
|
||||
obj_class->dispose = lsi_settings_window_dispose;
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_settings_window_init:
|
||||
*
|
||||
* Handle construction of the LsiSettingsWindow
|
||||
*/
|
||||
static void lsi_settings_window_init(LsiSettingsWindow *self)
|
||||
{
|
||||
GtkWidget *grid = NULL;
|
||||
GtkWidget *layout = NULL;
|
||||
GtkWidget *header = NULL;
|
||||
GtkWidget *widget = NULL;
|
||||
GtkStyleContext *style = NULL;
|
||||
const gchar *xdg_desktop = NULL;
|
||||
const gchar *emul32_desc = NULL;
|
||||
bool is_64bit = false;
|
||||
gchar *label = NULL;
|
||||
int row = 0;
|
||||
|
||||
/* Ensure we correctly clean this up.. */
|
||||
memset(&self->config, 0, sizeof(LsiConfig));
|
||||
|
||||
/* Load the LSI configuration now */
|
||||
if (!lsi_config_load(&self->config)) {
|
||||
lsi_config_load_defaults(&self->config);
|
||||
}
|
||||
|
||||
/* Conditionally apply CSD */
|
||||
#if GTK_CHECK_VERSION(3, 12, 0)
|
||||
xdg_desktop = g_getenv("XDG_CURRENT_DESKTOP");
|
||||
if (xdg_desktop && (strstr(xdg_desktop, "GNOME:") || strstr(xdg_desktop, ":GNOME") ||
|
||||
g_str_equal(xdg_desktop, "GNOME"))) {
|
||||
widget = gtk_header_bar_new();
|
||||
gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(widget), TRUE);
|
||||
gtk_window_set_titlebar(GTK_WINDOW(self), widget);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* For now we'll just exit on close */
|
||||
g_signal_connect(self, "delete-event", G_CALLBACK(lsi_window_closed), NULL);
|
||||
|
||||
/* Sort out window bits */
|
||||
gtk_window_set_title(GTK_WINDOW(self), _("Linux Steam® Integration"));
|
||||
gtk_window_set_icon_name(GTK_WINDOW(self), "steam");
|
||||
gtk_window_set_position(GTK_WINDOW(self), GTK_WIN_POS_CENTER);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(self), 320, 500);
|
||||
gtk_window_set_resizable(GTK_WINDOW(self), FALSE);
|
||||
|
||||
/* Add main layout */
|
||||
layout = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(self), layout);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(self), 12);
|
||||
gtk_widget_set_valign(GTK_WIDGET(layout), GTK_ALIGN_START);
|
||||
|
||||
/* Header box */
|
||||
header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_pack_start(GTK_BOX(layout), header, FALSE, FALSE, 0);
|
||||
|
||||
/* header label */
|
||||
label = g_strdup_printf("<big>%s</big>", _("Linux Steam® Integration"));
|
||||
widget = gtk_label_new(label);
|
||||
gtk_label_set_use_markup(GTK_LABEL(widget), TRUE);
|
||||
g_free(label);
|
||||
_align_label(widget);
|
||||
gtk_box_pack_start(GTK_BOX(header), widget, FALSE, FALSE, 0);
|
||||
|
||||
/* header image */
|
||||
widget = gtk_image_new_from_icon_name("steam", GTK_ICON_SIZE_DIALOG);
|
||||
gtk_widget_set_valign(widget, GTK_ALIGN_START);
|
||||
gtk_box_pack_end(GTK_BOX(header), widget, FALSE, FALSE, 0);
|
||||
|
||||
/* small label */
|
||||
widget = gtk_label_new(
|
||||
_("Control the behaviour of the Steam client and games. Settings will not take effect "
|
||||
"until the Steam Client is restarted. Use the 'Exit Steam' option to ensure it "
|
||||
"closes."));
|
||||
g_object_set(widget, "xalign", 0.0, NULL);
|
||||
gtk_label_set_max_width_chars(GTK_LABEL(widget), 80);
|
||||
gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);
|
||||
gtk_label_set_line_wrap_mode(GTK_LABEL(widget), PANGO_WRAP_WORD);
|
||||
_align_label(widget);
|
||||
gtk_box_pack_start(GTK_BOX(layout), widget, TRUE, TRUE, 0);
|
||||
style = gtk_widget_get_style_context(widget);
|
||||
gtk_style_context_add_class(style, GTK_STYLE_CLASS_DIM_LABEL);
|
||||
#if GTK_CHECK_VERSION(3, 12, 0)
|
||||
gtk_widget_set_margin_end(widget, 100);
|
||||
#else
|
||||
gtk_widget_set_margin_right(widget, 100);
|
||||
#endif
|
||||
/* add a separator now */
|
||||
widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_pack_start(GTK_BOX(layout), widget, FALSE, FALSE, 0);
|
||||
g_object_set(widget, "margin-top", 12, "margin-bottom", 4, NULL);
|
||||
|
||||
/* Start populating main grid with controls */
|
||||
grid = gtk_grid_new();
|
||||
gtk_box_pack_start(GTK_BOX(layout), grid, FALSE, FALSE, 0);
|
||||
|
||||
/* Start populating options into the UI */
|
||||
self->check_native = insert_grid_toggle(
|
||||
grid,
|
||||
&row,
|
||||
_("Use native runtime"),
|
||||
_("Switch between the native runtime and the bundled Steam runtime."));
|
||||
|
||||
/* Load in the existing configuration */
|
||||
gtk_switch_set_active(GTK_SWITCH(self->check_native), self->config.use_native_runtime);
|
||||
|
||||
is_64bit = lsi_system_is_64bit();
|
||||
/* Can only force on a 64-bit system. */
|
||||
if (!is_64bit) {
|
||||
/* Label is shown to indicate we can't enable 32-bit option */
|
||||
emul32_desc = _("This option has been disabled as the system is already 32-bit");
|
||||
} else {
|
||||
/* Label is shown on 64-bit systems only */
|
||||
emul32_desc =
|
||||
_("This may workaround some broken games, but will disable the Steam store "
|
||||
"browser.");
|
||||
}
|
||||
|
||||
self->check_emul32 =
|
||||
insert_grid_toggle(grid, &row, _("Force 32-bit mode for Steam"), emul32_desc);
|
||||
set_row_sensitive(self->check_emul32, is_64bit);
|
||||
gtk_switch_set_active(GTK_SWITCH(self->check_emul32), self->config.force_32);
|
||||
|
||||
#ifdef HAVE_LIBINTERCEPT
|
||||
self->check_intercept = insert_grid_toggle(
|
||||
grid,
|
||||
&row,
|
||||
_("Use the intercept library"),
|
||||
_("Force Steam applications to use more native libraries to maximise compatibility."));
|
||||
set_row_sensitive(self->check_intercept, FALSE);
|
||||
gtk_switch_set_active(GTK_SWITCH(self->check_intercept), self->config.use_libintercept);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBREDIRECT
|
||||
self->check_redirect =
|
||||
insert_grid_toggle(grid,
|
||||
&row,
|
||||
_("Use the redirect library"),
|
||||
_("Override system calls to fix known bugs in some "
|
||||
"Linux ports."));
|
||||
set_row_sensitive(self->check_redirect, FALSE);
|
||||
gtk_switch_set_active(GTK_SWITCH(self->check_redirect), self->config.use_libredirect);
|
||||
#endif
|
||||
|
||||
/* Hook up our signals. Basically the "native runtime" option controls the two library
|
||||
* options, they must be used in conjunction.
|
||||
*/
|
||||
g_signal_connect_swapped(self->check_native,
|
||||
"notify::active",
|
||||
G_CALLBACK(lsi_native_swapped),
|
||||
self);
|
||||
|
||||
/* Ensure our properties are now in sync. */
|
||||
lsi_native_swapped(self, self->check_native);
|
||||
|
||||
/* Finally, make sure we're visible will we. */
|
||||
gtk_widget_show_all(GTK_WIDGET(self));
|
||||
}
|
||||
|
||||
static void _align_label(GtkWidget *label)
|
||||
{
|
||||
#if GTK_CHECK_VERSION(3, 12, 0)
|
||||
gtk_widget_set_halign(label, GTK_ALIGN_START);
|
||||
#else
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
|
||||
#endif
|
||||
gtk_widget_set_hexpand(label, FALSE);
|
||||
gtk_widget_set_valign(label, GTK_ALIGN_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic function to add titled description box with a custom widget into the grid.
|
||||
*/
|
||||
static void insert_grid(GtkWidget *grid, int *row, const char *title, const char *description,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *label = NULL;
|
||||
GtkWidget *desc = NULL;
|
||||
GtkStyleContext *style = NULL;
|
||||
|
||||
/* Sort out title label */
|
||||
label = gtk_label_new(title);
|
||||
_align_label(label);
|
||||
g_object_set(label, "margin-top", 12, "hexpand", TRUE, NULL);
|
||||
gtk_grid_attach(GTK_GRID(grid), label, 0, *row, 1, 1);
|
||||
|
||||
g_object_set(widget,
|
||||
"halign",
|
||||
GTK_ALIGN_END,
|
||||
"valign",
|
||||
GTK_ALIGN_END,
|
||||
"vexpand",
|
||||
FALSE,
|
||||
NULL);
|
||||
gtk_grid_attach(GTK_GRID(grid), widget, 1, *row, 1, 1);
|
||||
|
||||
*row += 1;
|
||||
|
||||
/* Sort out description label */
|
||||
desc = gtk_label_new(description);
|
||||
_align_label(desc);
|
||||
style = gtk_widget_get_style_context(desc);
|
||||
gtk_style_context_add_class(style, GTK_STYLE_CLASS_DIM_LABEL);
|
||||
#if GTK_CHECK_VERSION(3, 12, 0)
|
||||
gtk_widget_set_margin_end(desc, 12);
|
||||
#else
|
||||
gtk_widget_set_margin_right(desc, 12);
|
||||
#endif
|
||||
/* Deprecated but line wrap is busted without it.. */
|
||||
g_object_set(desc, "xalign", 0.0, NULL);
|
||||
gtk_label_set_line_wrap(GTK_LABEL(desc), TRUE);
|
||||
gtk_label_set_line_wrap_mode(GTK_LABEL(desc), PANGO_WRAP_WORD);
|
||||
gtk_label_set_max_width_chars(GTK_LABEL(desc), 90);
|
||||
|
||||
gtk_grid_attach(GTK_GRID(grid), desc, 0, *row, 1, 1);
|
||||
*row += 1;
|
||||
|
||||
/* Allow accessing these dynamic items again */
|
||||
g_object_set_data(G_OBJECT(widget), "lsi_title", label);
|
||||
g_object_set_data(G_OBJECT(widget), "lsi_desc", desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the complete row within the grid to the given sensitivity state
|
||||
*/
|
||||
static void set_row_sensitive(GtkWidget *toggle, gboolean sensitive)
|
||||
{
|
||||
GtkWidget *title = NULL;
|
||||
GtkWidget *desc = NULL;
|
||||
|
||||
title = g_object_get_data(G_OBJECT(toggle), "lsi_title");
|
||||
desc = g_object_get_data(G_OBJECT(toggle), "lsi_desc");
|
||||
|
||||
gtk_widget_set_sensitive(toggle, sensitive);
|
||||
gtk_widget_set_sensitive(title, sensitive);
|
||||
gtk_widget_set_sensitive(desc, sensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds on the insert_grid function to insert a GtkSwitch and return only the
|
||||
* switch widget.
|
||||
*/
|
||||
static GtkWidget *insert_grid_toggle(GtkWidget *grid, int *row, const char *title,
|
||||
const char *description)
|
||||
{
|
||||
GtkWidget *toggle = NULL;
|
||||
|
||||
/* Sort out widget */
|
||||
toggle = gtk_switch_new();
|
||||
insert_grid(grid, row, title, description, toggle);
|
||||
return toggle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the sensitivity of the UI controls based on whether or not we have
|
||||
* native runtime turned on
|
||||
*/
|
||||
static void lsi_native_swapped(LsiSettingsWindow *self, __lsi_unused__ gpointer v)
|
||||
{
|
||||
gboolean native_runtime;
|
||||
|
||||
native_runtime = gtk_switch_get_active(GTK_SWITCH(self->check_native));
|
||||
|
||||
#ifdef HAVE_LIBREDIRECT
|
||||
set_row_sensitive(self->check_redirect, native_runtime);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBINTERCEPT
|
||||
set_row_sensitive(self->check_intercept, native_runtime);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Window is closed, so let's write our config out
|
||||
*/
|
||||
static gboolean lsi_window_closed(LsiSettingsWindow *self, __lsi_unused__ GdkEvent *event,
|
||||
__lsi_unused__ gpointer v)
|
||||
{
|
||||
/* Just pop the properties back into the struct */
|
||||
self->config.force_32 = gtk_switch_get_active(GTK_SWITCH(self->check_emul32));
|
||||
self->config.use_native_runtime = gtk_switch_get_active(GTK_SWITCH(self->check_native));
|
||||
|
||||
#ifdef HAVE_LIBREDIRECT
|
||||
self->config.use_libredirect = gtk_switch_get_active(GTK_SWITCH(self->check_redirect));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBINTERCEPT
|
||||
self->config.use_libredirect = gtk_switch_get_active(GTK_SWITCH(self->check_redirect));
|
||||
#endif
|
||||
|
||||
/* Try to write new config */
|
||||
if (!lsi_config_store(&self->config)) {
|
||||
lsi_report_failure("%s: %s", _("Failed to save configuration"), strerror(errno));
|
||||
}
|
||||
|
||||
gtk_main_quit();
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _LsiSettingsWindow LsiSettingsWindow;
|
||||
typedef struct _LsiSettingsWindowClass LsiSettingsWindowClass;
|
||||
|
||||
#define LSI_TYPE_SETTINGS_WINDOW lsi_settings_window_get_type()
|
||||
#define LSI_SETTINGS_WINDOW(o) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((o), LSI_TYPE_SETTINGS_WINDOW, LsiSettingsWindow))
|
||||
#define LSI_IS_SETTINGS_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), LSI_TYPE_SETTINGS_WINDOW))
|
||||
#define LSI_SETTINGS_WINDOW_CLASS(o) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((o), LSI_TYPE_SETTINGS_WINDOW, LsiSettingsWindowClass))
|
||||
#define LSI_IS_SETTINGS_WINDOW_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE((o), LSI_TYPE_SETTINGS_WINDOW))
|
||||
#define LSI_SETTINGS_WINDOW_GET_CLASS(o) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS((o), LSI_TYPE_SETTINGS_WINDOW, LsiSettingsWindowClass))
|
||||
|
||||
GtkWidget *lsi_settings_window_new(void);
|
||||
|
||||
GType lsi_settings_window_get_type(void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
+17
-124
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016 Ikey Doherty
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
@@ -11,138 +11,31 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lsi.h"
|
||||
|
||||
static inline void _align_label(GtkWidget *label)
|
||||
{
|
||||
#if GTK_MINOR_VERSION <= 12
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
|
||||
#else
|
||||
gtk_widget_set_halign(label, GTK_ALIGN_START);
|
||||
#endif
|
||||
gtk_widget_set_hexpand(label, FALSE);
|
||||
gtk_widget_set_valign(label, GTK_ALIGN_START);
|
||||
}
|
||||
#include "config.h"
|
||||
#include "main-window.h"
|
||||
|
||||
/**
|
||||
* Main application entry.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window = NULL;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
GtkWidget *dialog = NULL;
|
||||
GtkWidget *grid = NULL;
|
||||
GtkWidget *container = NULL;
|
||||
GtkWidget *button = NULL;
|
||||
GtkWidget *image = NULL;
|
||||
GtkWidget *check_native = NULL;
|
||||
GtkWidget *check_emul32 = NULL;
|
||||
GtkWidget *label = NULL;
|
||||
GtkSettings *settings = NULL;
|
||||
int response = 0;
|
||||
bool is_x86_64 = lsi_system_is_64bit();
|
||||
LsiConfig lconfig = { 0 };
|
||||
|
||||
dialog = gtk_dialog_new();
|
||||
g_object_set(G_OBJECT(dialog),
|
||||
"title",
|
||||
"Linux Steam® Integration",
|
||||
"icon-name",
|
||||
"steam",
|
||||
NULL);
|
||||
window = lsi_settings_window_new();
|
||||
gtk_widget_show(window);
|
||||
|
||||
settings = gtk_settings_get_default();
|
||||
g_object_set(settings, "gtk-application-prefer-dark-theme", TRUE, NULL);
|
||||
gtk_main();
|
||||
|
||||
/* Sort out the buttons */
|
||||
(void)gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", GTK_RESPONSE_REJECT);
|
||||
button = gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_ACCEPT);
|
||||
gtk_style_context_add_class(gtk_widget_get_style_context(button), "suggested-action");
|
||||
|
||||
/* Pack the grid */
|
||||
grid = gtk_grid_new();
|
||||
gtk_grid_set_column_spacing(GTK_GRID(grid), 12);
|
||||
gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
|
||||
|
||||
container = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
gtk_container_add(GTK_CONTAINER(container), grid);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(container), 6);
|
||||
|
||||
/* Add a splash of colour. */
|
||||
image = gtk_image_new_from_icon_name("steam", GTK_ICON_SIZE_DIALOG);
|
||||
gtk_image_set_pixel_size(GTK_IMAGE(image), 64);
|
||||
gtk_grid_attach(GTK_GRID(grid), image, 0, 0, 1, 1);
|
||||
|
||||
label = gtk_label_new(
|
||||
"<big>Linux Steam® Integration</big>\n"
|
||||
"Note that settings are not applied until the next time Steam® starts.\n"
|
||||
"Use the \'Exit Steam\' option on the Steam® tray icon to exit the application.");
|
||||
_align_label(label);
|
||||
gtk_grid_attach(GTK_GRID(grid), label, 1, 0, 2, 1);
|
||||
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
|
||||
gtk_widget_set_margin_bottom(label, 8);
|
||||
|
||||
label = gtk_label_new("Use the native runtime provided by the Operating System");
|
||||
_align_label(label);
|
||||
gtk_widget_set_tooltip_text(label,
|
||||
"Alternatively, the default Steam® runtime "
|
||||
"will be used, which may cause issues.");
|
||||
gtk_grid_attach(GTK_GRID(grid), label, 1, 1, 1, 1);
|
||||
check_native = gtk_switch_new();
|
||||
gtk_grid_attach(GTK_GRID(grid), check_native, 2, 1, 1, 1);
|
||||
|
||||
/* Handle the 32-bit cruft */
|
||||
label = gtk_label_new("Force 32-bit mode for Steam®");
|
||||
_align_label(label);
|
||||
if (is_x86_64) {
|
||||
gtk_widget_set_tooltip_text(label,
|
||||
"Some games may run better using 32-bit than 64-bit");
|
||||
} else {
|
||||
gtk_widget_set_tooltip_text(label, "You are using a 32-bit operating system");
|
||||
}
|
||||
|
||||
gtk_grid_attach(GTK_GRID(grid), label, 1, 2, 1, 1);
|
||||
check_emul32 = gtk_switch_new();
|
||||
gtk_grid_attach(GTK_GRID(grid), check_emul32, 2, 2, 1, 1);
|
||||
|
||||
gtk_widget_set_sensitive(label, is_x86_64);
|
||||
gtk_widget_set_sensitive(check_emul32, is_x86_64);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(grid), 6);
|
||||
gtk_widget_set_margin_bottom(grid, 18);
|
||||
|
||||
/* Load the config */
|
||||
if (!lsi_config_load(&lconfig)) {
|
||||
lsi_config_load_defaults(&lconfig);
|
||||
}
|
||||
|
||||
/* Adapt UI to match config */
|
||||
gtk_switch_set_active(GTK_SWITCH(check_native), lconfig.use_native_runtime);
|
||||
gtk_switch_set_active(GTK_SWITCH(check_emul32), lconfig.force_32);
|
||||
|
||||
/* Run the dialog */
|
||||
gtk_widget_show_all(container);
|
||||
response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
if (response == GTK_RESPONSE_REJECT) {
|
||||
gtk_widget_destroy(dialog);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get the config from the UI */
|
||||
lconfig.use_native_runtime = gtk_switch_get_active(GTK_SWITCH(check_native));
|
||||
lconfig.force_32 = gtk_switch_get_active(GTK_SWITCH(check_emul32));
|
||||
|
||||
/* Cleanup */
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
/* Try to write new config */
|
||||
if (!lsi_config_store(&lconfig)) {
|
||||
lsi_report_failure("Failed to save configuration: %s", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
if with_frontend == true
|
||||
dep_gtk3 = dependency('gtk+-3.0', version: '>= 3.4.0')
|
||||
|
||||
frontend_sources = [
|
||||
'main.c',
|
||||
'main-window.c',
|
||||
]
|
||||
|
||||
frontend = executable(
|
||||
'lsi-settings',
|
||||
sources: frontend_sources + nica_sources,
|
||||
include_directories: nica_includes,
|
||||
dependencies: [
|
||||
dep_gtk3,
|
||||
link_lsi,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
endif
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <libgen.h>
|
||||
#include <link.h>
|
||||
#include <linux/limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../common/files.h"
|
||||
#include "../common/log.h"
|
||||
#include "config.h"
|
||||
#include "nica/util.h"
|
||||
|
||||
/**
|
||||
* What's the known process name?
|
||||
*/
|
||||
static const char *matched_process = NULL;
|
||||
|
||||
/**
|
||||
* We support a number of modes, but we mostly exist to make Steam behave
|
||||
*/
|
||||
typedef enum {
|
||||
INTERCEPT_MODE_NONE = 0,
|
||||
INTERCEPT_MODE_STEAM,
|
||||
INTERCEPT_MODE_VENDOR_OFFENDER,
|
||||
} InterceptMode;
|
||||
|
||||
/**
|
||||
* by default, we're not "on"
|
||||
*/
|
||||
static InterceptMode work_mode = INTERCEPT_MODE_NONE;
|
||||
|
||||
/* Patterns we'll permit Steam to privately load */
|
||||
static const char *steam_allowed[] = {
|
||||
/* general */
|
||||
"libicui18n.so",
|
||||
"libicuuc.so",
|
||||
"libavcodec.so.",
|
||||
"libavformat.so.",
|
||||
"libavresample.so.",
|
||||
"libavutil.so.",
|
||||
"libswscale.so.",
|
||||
"libx264.so.",
|
||||
|
||||
/* core plugins */
|
||||
"chromehtml.so",
|
||||
"crashhandler.so",
|
||||
"filesystem_stdio.so",
|
||||
"friendsui.so",
|
||||
"gameoverlayrenderer.so",
|
||||
"gameoverlayui.so",
|
||||
"libaudio.so",
|
||||
"libmiles.so",
|
||||
"libopenvr_api.so",
|
||||
"liboverride.so",
|
||||
"libsteam.so",
|
||||
"libtier0_s.so",
|
||||
"libv8.so",
|
||||
"libvideo.so",
|
||||
"libvstdlib_s.so",
|
||||
"serverbrowser.so",
|
||||
"steamclient.so",
|
||||
"steamoverlayvulkanlayer.so",
|
||||
"steamservice.so",
|
||||
"steamui.so",
|
||||
"vgui2_s.so",
|
||||
|
||||
/* big picture mode */
|
||||
"panorama",
|
||||
"libpangoft2-1.0.so",
|
||||
"libpango-1.0.so",
|
||||
|
||||
/* steamwebhelper */
|
||||
"libcef.so",
|
||||
|
||||
/* Swift shader */
|
||||
"libGLESv2.so",
|
||||
};
|
||||
|
||||
static const char *wanted_steam_processes[] = {
|
||||
"html5app_steam",
|
||||
"opengl-program",
|
||||
"steam",
|
||||
"steamwebhelper",
|
||||
};
|
||||
|
||||
/**
|
||||
* Vendor offendors should not be allowed to load replacements for libraries
|
||||
* that are KNOWN to cause issues, i.e. SDL + libstdc++
|
||||
*/
|
||||
static const char *vendor_blacklist[] = {
|
||||
/* base libraries being replaced will cause a C++ ABI issue when
|
||||
* loading the mesalib drivers. */
|
||||
"libgcc_",
|
||||
"libstdc++",
|
||||
"libSDL",
|
||||
|
||||
/* general problem causer. */
|
||||
"libopenal.so.",
|
||||
|
||||
/* thou shalt not replace drivers (swiftshader) ! */
|
||||
"libGLESv2.so",
|
||||
"libGL.so",
|
||||
|
||||
/* glews (provide glew + glew110 in your distro for full compat) */
|
||||
"libGLEW.so.1.10",
|
||||
"libGLEW.so.1.12",
|
||||
|
||||
/* libglu has stable soname */
|
||||
"libGLU.so.",
|
||||
|
||||
/* Security sensitive libraries should not be replaced */
|
||||
"libcurl.so.",
|
||||
|
||||
#ifdef LSI_OVERRIDE_LIBRESSL
|
||||
/* Sometimes libressl but this is handled separately. */
|
||||
"libcrypto.so.",
|
||||
"libssl.so.",
|
||||
#else
|
||||
"libcrypto.so.1.0.0",
|
||||
"libssl.so.1.0.0",
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if we're in a given process set, i.e. the process name matches
|
||||
* the given table
|
||||
*/
|
||||
static bool is_in_process_set(char *process_name, const char **processes, size_t n_processes)
|
||||
{
|
||||
/* Are we some portion of the process set? */
|
||||
for (size_t i = 0; i < n_processes; i++) {
|
||||
if (streq(processes[i], process_name)) {
|
||||
work_mode = INTERCEPT_MODE_STEAM;
|
||||
matched_process = processes[i];
|
||||
lsi_log_debug("loading libintercept for '%s'", matched_process);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if we're being executed by a process we actually need to override,
|
||||
* otherwise we'd not be loaded by rtld-audit
|
||||
*/
|
||||
static void check_is_intercept_candidate(void)
|
||||
{
|
||||
autofree(char) *nom = NULL;
|
||||
|
||||
nom = lsi_get_process_base_name();
|
||||
if (!nom) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_in_process_set(nom, wanted_steam_processes, ARRAY_SIZE(wanted_steam_processes))) {
|
||||
work_mode = INTERCEPT_MODE_STEAM;
|
||||
} else {
|
||||
work_mode = INTERCEPT_MODE_VENDOR_OFFENDER;
|
||||
matched_process = "vendor_offender";
|
||||
}
|
||||
lsi_log_set_id(matched_process);
|
||||
}
|
||||
|
||||
/**
|
||||
* la_version is our main entry point and will only continue if our
|
||||
* process is explicitly Steam
|
||||
*/
|
||||
_nica_public_ unsigned int la_version(unsigned int supported_version)
|
||||
{
|
||||
/* Unfortunately glibc will die if we tell it to skip us .. */
|
||||
check_is_intercept_candidate();
|
||||
return supported_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_search_steam handles whitelisting for the main Steam processes
|
||||
*/
|
||||
char *lsi_search_steam(const char *name)
|
||||
{
|
||||
/* Find out if it exists */
|
||||
bool file_exists = lsi_file_exists(name);
|
||||
|
||||
/* Find out if its a Steam private lib.. These are relative "./" files too! */
|
||||
if (name && (strstr(name, "/Steam/") || strncmp(name, "./", 2) == 0)) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(steam_allowed); i++) {
|
||||
if (strstr(name, steam_allowed[i])) {
|
||||
return (char *)name;
|
||||
}
|
||||
}
|
||||
if (file_exists) {
|
||||
lsi_log_debug("blacklisted loading of vendor library: \033[34;1m%s\033[0m",
|
||||
name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Source identifier patterns that indicate a soname replacement is happening.
|
||||
* Note that this is a basic pattern match for the soname and just allows us
|
||||
* to lookup the transmute target
|
||||
*/
|
||||
static const char *vendor_transmute_source[] = {
|
||||
/* Common */
|
||||
"libSDL2-2.0.",
|
||||
"libSDL2_image-2.0.",
|
||||
|
||||
/* ".so" renames */
|
||||
"libSDL2_ttf.so",
|
||||
"libSDL2_image.so",
|
||||
"libSDL2_mixer.so",
|
||||
"libSDL2_net.so",
|
||||
"libSDL2_gfx.so",
|
||||
|
||||
/* libressl (security updates) */
|
||||
#ifdef LSI_OVERRIDE_LIBRESSL
|
||||
"libcrypto.so.36",
|
||||
"libssl.so.37",
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* The transmute target is the intended replacement for any source name, assuming
|
||||
* that the soname doesn't identically match the currently requested soname.
|
||||
* This allows us to do on the fly replacements for re-soname'd libraries.
|
||||
*/
|
||||
static const char *vendor_transmute_target[] = {
|
||||
/* Common */
|
||||
"libSDL2-2.0.so.0",
|
||||
"libSDL2_image-2.0.so.0",
|
||||
|
||||
/* ".so" renames */
|
||||
"libSDL2_ttf-2.0.so.0",
|
||||
"libSDL2_image-2.0.so.0",
|
||||
"libSDL2_mixer-2.0.so.0",
|
||||
"libSDL2_net-2.0.so.0",
|
||||
"libSDL2_gfx-1.0.so.0",
|
||||
|
||||
/* libressl (security updates) */
|
||||
#if defined(LSI_LIBRESSL_MODE_SHIM)
|
||||
"libcrypto" LSI_LIBRESSL_SUFFIX ".so",
|
||||
"libssl" LSI_LIBRESSL_SUFFIX ".so",
|
||||
#elif defined(LSI_LIBRESSL_MODE_NATIVE)
|
||||
"libcrypto.so.1.0.0",
|
||||
"libssl.so.1.0.0",
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Every so often a game comes along that does the following:
|
||||
*
|
||||
* open("path") ? dlopen("path").
|
||||
* Except: path = "*.dll", dlopen() is transformed to ".dll.so"
|
||||
*
|
||||
* This is unrelated to the ".la" errors
|
||||
*/
|
||||
static bool lsi_override_dll_fail(const char *orig_name, const char **soname)
|
||||
{
|
||||
size_t len = strlen(orig_name);
|
||||
static char path_lookup[PATH_MAX];
|
||||
|
||||
if (len < 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp(orig_name + (len - 7), ".dll.so", 7) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strncpy(path_lookup, orig_name, len - 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lsi_file_exists(path_lookup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*soname = path_lookup;
|
||||
lsi_log_debug("fixed invalid suffix dlopen() \033[31;1m%s\033[0m -> \033[34;1m%s\033[0m",
|
||||
orig_name,
|
||||
path_lookup);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mono games might try looking for /x86/ plugin directory for a 64-bit process,
|
||||
* as seen with testing with Project Highrise.
|
||||
*
|
||||
* This function simply redirects the dlopen to the file in the x86_64 directory,
|
||||
* if it actually exists.
|
||||
*
|
||||
* Typically this is for libCSteamWorks, libsteam_api, and Unity ScreenSelector.so
|
||||
*/
|
||||
#if UINTPTR_MAX == 0xffffffffffffffff
|
||||
static bool lsi_override_x86_derp(const char *orig_name, const char **soname)
|
||||
{
|
||||
static char path_copy[PATH_MAX];
|
||||
static char path_lookup[PATH_MAX];
|
||||
char *small_name = NULL;
|
||||
char *dir = NULL;
|
||||
|
||||
if (!(strstr(orig_name, "/Plugins/x86/") && strstr(orig_name, ".so"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcpy(path_copy, orig_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
small_name = basename(path_copy);
|
||||
dir = dirname(path_copy);
|
||||
|
||||
if (snprintf(path_lookup, sizeof(path_lookup), "%s/../x86_64/%s", dir, small_name) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lsi_file_exists(path_lookup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*soname = path_lookup;
|
||||
lsi_log_debug(
|
||||
"fixed invalid architecture dlopen() \033[31;1m%s\033[0m -> \033[34;1m%s\033[0m",
|
||||
orig_name,
|
||||
path_lookup);
|
||||
return true;
|
||||
#else
|
||||
static bool lsi_override_x86_derp(__lsi_unused__ const char *orig_name,
|
||||
__lsi_unused__ const char **soname)
|
||||
{
|
||||
/* Don't perform x86 translation on 32-bit machines */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_override_dlopen is used to override simple dlopen() requests typically
|
||||
* used by Mono games, i.e.:
|
||||
*
|
||||
* <dllmap dll="SDL2.dll" os="linux" cpu="x86-64" target="./lib64/libSDL2-2.0.so.0"/>
|
||||
*
|
||||
* We'll attempt to do a trivial lookup for "/usr/./lib64/libSDL2-2.0.so.0 in this
|
||||
* case.
|
||||
*/
|
||||
static bool lsi_override_dlopen(const char *orig_name, const char **soname)
|
||||
{
|
||||
static char path_lookup[PATH_MAX];
|
||||
static char path_copy[PATH_MAX];
|
||||
char *small_name = NULL;
|
||||
static const char *library_paths[] = {
|
||||
#if UINTPTR_MAX == 0xffffffffffffffff
|
||||
"/usr/lib64",
|
||||
"/usr/lib/x86_64-linux-gnu",
|
||||
"/usr/lib",
|
||||
#else
|
||||
"/usr/lib32",
|
||||
"/usr/lib/i386-linux-gnu",
|
||||
"/usr/lib",
|
||||
#endif
|
||||
};
|
||||
|
||||
if (lsi_override_dll_fail(orig_name, soname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!lsi_file_exists(orig_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lsi_override_x86_derp(orig_name, soname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcpy(path_copy, orig_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
small_name = basename(path_copy);
|
||||
|
||||
/* Iterate all of the library paths for this process architecture and try
|
||||
* to find a system variant of the library instead of allowing the process
|
||||
* to dlopen() the vendored version.
|
||||
*/
|
||||
for (size_t i = 0; i < ARRAY_SIZE(library_paths); i++) {
|
||||
if (snprintf(path_lookup,
|
||||
sizeof(path_lookup),
|
||||
"%s/%s",
|
||||
library_paths[i],
|
||||
small_name) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!lsi_file_exists(path_lookup)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We hit a match but it was identical to our expectation */
|
||||
if (strcmp(path_lookup, orig_name) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*soname = path_lookup;
|
||||
lsi_log_debug(
|
||||
"intercepting vendor dlopen() \033[31;1m%s\033[0m -> \033[34;1m%s\033[0m",
|
||||
orig_name,
|
||||
path_lookup);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* lsi_override_soname will deal with LA_SER_ORIG entries, i.e. the original
|
||||
* soname request when the linker tries to load a library.
|
||||
*
|
||||
* Certain Steam games (notably Feral Interactive ports) use their own vendored
|
||||
* SDL libraries with changed sonames, which are implicitly blacklisted by the
|
||||
* lsi_blacklist_vendor function.
|
||||
*
|
||||
* As such, we intercept those renamed libraries, and convert their names back
|
||||
* to the ABI stable system libraries on the fly.
|
||||
*/
|
||||
static bool lsi_override_soname(unsigned int flag, const char *orig_name, const char **soname)
|
||||
{
|
||||
*soname = NULL;
|
||||
|
||||
/* We only need to deal with LA_SER_ORIG */
|
||||
if ((flag & LA_SER_ORIG) != LA_SER_ORIG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Don't transform dlopen */
|
||||
if (strstr(orig_name, "/")) {
|
||||
return lsi_override_dlopen(orig_name, soname);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(vendor_transmute_source); i++) {
|
||||
if (!strstr(orig_name, vendor_transmute_source[i])) {
|
||||
continue;
|
||||
}
|
||||
/* Ensure we're not just replacing the same thing here as the
|
||||
* string would be identical, no real replacement would happen,
|
||||
* and ld will be confused about memory and die.
|
||||
*/
|
||||
if (streq(orig_name, vendor_transmute_target[i])) {
|
||||
continue;
|
||||
}
|
||||
*soname = vendor_transmute_target[i];
|
||||
lsi_log_debug(
|
||||
"transforming vendor soname: \033[31;1m%s\033[0m -> \033[34;1m%s\033[0m",
|
||||
orig_name,
|
||||
*soname);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *lsi_blacklist_vendor(unsigned int flag, const char *name)
|
||||
{
|
||||
/* Find out if it exists */
|
||||
bool file_exists = lsi_file_exists(name);
|
||||
const char *override_soname = NULL;
|
||||
|
||||
/* Find out if we have to rename some libraries on the fly */
|
||||
if (lsi_override_soname(flag, name, &override_soname)) {
|
||||
return (char *)override_soname;
|
||||
}
|
||||
|
||||
/* Find out if its a Steam private lib.. These are relative "./" files too! */
|
||||
if (name && (strstr(name, "/Steam/") || strncmp(name, "./", 2) == 0)) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(vendor_blacklist); i++) {
|
||||
if (!strstr(name, vendor_blacklist[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file_exists) {
|
||||
lsi_log_debug(
|
||||
"blacklisted loading of vendor library: \033[34;1m%s\033[0m",
|
||||
name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* Allowed to exist */
|
||||
return (char *)name;
|
||||
}
|
||||
|
||||
return (char *)name;
|
||||
}
|
||||
|
||||
/**
|
||||
* la_objsearch will allow us to blacklist certain LD_LIBRARY_PATH duplicate
|
||||
* libraries being loaded by the Steam client, such as the broken libSDL shipped
|
||||
* as a private vendored lib
|
||||
*/
|
||||
_nica_public_ char *la_objsearch(const char *name, __lsi_unused__ uintptr_t *cookie,
|
||||
unsigned int flag)
|
||||
{
|
||||
switch (work_mode) {
|
||||
case INTERCEPT_MODE_STEAM:
|
||||
return lsi_search_steam(name);
|
||||
case INTERCEPT_MODE_VENDOR_OFFENDER:
|
||||
return lsi_blacklist_vendor(flag, name);
|
||||
case INTERCEPT_MODE_NONE:
|
||||
default:
|
||||
return (char *)name;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,22 @@
|
||||
# Only build libintercept if told to!
|
||||
|
||||
if with_libintercept == true
|
||||
|
||||
intercept_sources = [
|
||||
'main.c',
|
||||
]
|
||||
|
||||
sym_map = join_paths(meson.current_source_dir(), 'sym.map')
|
||||
|
||||
main_intercept = shared_library(
|
||||
'lsi-intercept',
|
||||
sources: intercept_sources,
|
||||
c_args: ['-fvisibility=hidden'],
|
||||
link_args: ['-Wl,--version-script=@0@'.format(sym_map)],
|
||||
include_directories: nica_includes,
|
||||
dependencies: [
|
||||
link_lsi_common,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
endif
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
global:
|
||||
la_objsearch;
|
||||
la_version;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
Submodule
+1
Submodule src/libnica added at e71a442667
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016 Ikey Doherty
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "nica/hashmap.h"
|
||||
#include "nica/inifile.h"
|
||||
|
||||
#include "../common/files.h"
|
||||
|
||||
/**
|
||||
* Configuration file suffix, i.e. ~/.config/linux-steam-integration.conf
|
||||
*/
|
||||
@@ -42,38 +44,6 @@
|
||||
*/
|
||||
#define LSI_VENDOR_CONFIG_FILE VENDORDIR "/ " LSI_CONFIG_FILE
|
||||
|
||||
/**
|
||||
* Determine the home directory
|
||||
*/
|
||||
static const char *lsi_get_home_dir(void)
|
||||
{
|
||||
char *c = NULL;
|
||||
struct passwd *p = NULL;
|
||||
|
||||
c = getenv("HOME");
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
p = getpwuid(getuid());
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
return p->pw_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the home config directory
|
||||
*/
|
||||
static char *lsi_get_user_config_dir(void)
|
||||
{
|
||||
const char *home = lsi_get_home_dir();
|
||||
char *c = NULL;
|
||||
if (asprintf(&c, "%s/.config", home) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the user config file path
|
||||
*/
|
||||
@@ -143,6 +113,20 @@ bool lsi_config_load(LsiConfig *config)
|
||||
map_val = NULL;
|
||||
}
|
||||
|
||||
/* Do we want libintercept? */
|
||||
map_val = nc_hashmap_get(nc_hashmap_get(mconfig, "Steam"), "use-libintercept");
|
||||
if (map_val) {
|
||||
config->use_libintercept = lsi_is_boolean_true(map_val);
|
||||
map_val = NULL;
|
||||
}
|
||||
|
||||
/* Do we want libredirect? */
|
||||
map_val = nc_hashmap_get(nc_hashmap_get(mconfig, "Steam"), "use-libredirect");
|
||||
if (map_val) {
|
||||
config->use_libredirect = lsi_is_boolean_true(map_val);
|
||||
map_val = NULL;
|
||||
}
|
||||
|
||||
/* Check if 32-bit is being forced */
|
||||
map_val = nc_hashmap_get(nc_hashmap_get(mconfig, "Steam"), "force-32bit");
|
||||
if (map_val) {
|
||||
@@ -178,9 +162,12 @@ bool lsi_config_store(LsiConfig *config)
|
||||
return false;
|
||||
}
|
||||
if (fprintf(fp,
|
||||
"[Steam]\nuse-native-runtime = %s\nforce-32bit = %s\n",
|
||||
"[Steam]\nuse-native-runtime = %s\nforce-32bit = %s\nuse-libintercept = "
|
||||
"%s\nuse-libredirect = %s\n",
|
||||
lsi_bool_to_string(config->use_native_runtime),
|
||||
lsi_bool_to_string(config->force_32)) < 0) {
|
||||
lsi_bool_to_string(config->force_32),
|
||||
lsi_bool_to_string(config->use_libintercept),
|
||||
lsi_bool_to_string(config->use_libredirect)) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -194,6 +181,8 @@ void lsi_config_load_defaults(LsiConfig *config)
|
||||
* things that LSI knows about */
|
||||
config->force_32 = false;
|
||||
config->use_native_runtime = true;
|
||||
config->use_libintercept = true;
|
||||
config->use_libredirect = true;
|
||||
}
|
||||
|
||||
void lsi_report_failure(const char *s, ...)
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016 Ikey Doherty
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
@@ -16,25 +16,20 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "config.h"
|
||||
|
||||
/* Mark a variable/argument as unused to skip warnings */
|
||||
#define __lsi_unused__ __attribute__((unused))
|
||||
|
||||
/* Force inlining of a function */
|
||||
#define __lsi_inline__ __attribute__((always_inline))
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
/**
|
||||
* Current Linux Steam Integration settings.
|
||||
*/
|
||||
typedef struct LsiConfig {
|
||||
bool force_32; /**<Do we force 32-bit? */
|
||||
bool use_native_runtime; /**<Do we force our native runtime? */
|
||||
bool use_libintercept; /**<Do we force libintercept? */
|
||||
bool use_libredirect; /**<Do we force libredirect? */
|
||||
} LsiConfig;
|
||||
|
||||
/**
|
||||
@@ -101,15 +96,6 @@ __lsi_inline__ static inline const char *lsi_preload_list(void)
|
||||
*/
|
||||
void lsi_report_failure(const char *s, ...);
|
||||
|
||||
/**
|
||||
* Quick helper to determine if the path exists
|
||||
*/
|
||||
__lsi_inline__ static inline bool lsi_file_exists(const char *path)
|
||||
{
|
||||
__lsi_unused__ struct stat st = { 0 };
|
||||
return lstat(path, &st) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
@@ -0,0 +1,21 @@
|
||||
# Only build liblsi if told to!
|
||||
|
||||
if shim_behaviour != 'none' or with_frontend == true
|
||||
|
||||
lsi_sources = [
|
||||
'lsi.c',
|
||||
]
|
||||
|
||||
lib_lsi = static_library(
|
||||
'lsi-lsi',
|
||||
sources: lsi_sources,
|
||||
dependencies: [
|
||||
link_lsi_common,
|
||||
],
|
||||
include_directories: nica_includes,
|
||||
)
|
||||
link_lsi = declare_dependency(
|
||||
link_with: lib_lsi,
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
endif
|
||||
@@ -0,0 +1,24 @@
|
||||
# Track how to build nica, as we actually build it twice..
|
||||
|
||||
nica_sources = [
|
||||
'../libnica/src/array.c',
|
||||
'../libnica/src/hashmap.c',
|
||||
'../libnica/src/files.c',
|
||||
'../libnica/src/inifile.c',
|
||||
'../libnica/src/list.c',
|
||||
'../libnica/src/nc-string.c',
|
||||
'../libnica/src/util.c',
|
||||
]
|
||||
|
||||
nica_includes = [
|
||||
include_directories('libnica/src/include'),
|
||||
include_directories('libnica/src/include/nica'),
|
||||
config_h_dir,
|
||||
]
|
||||
|
||||
subdir('common')
|
||||
subdir('lsi')
|
||||
subdir('frontend')
|
||||
subdir('intercept')
|
||||
subdir('redirect')
|
||||
subdir('shim')
|
||||
@@ -1,472 +0,0 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* libnica is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
|
||||
#define INITIAL_SIZE 61
|
||||
|
||||
/* When we're "full", 70% */
|
||||
#define FULL_FACTOR 0.7
|
||||
|
||||
/* Multiple to increase bucket size by */
|
||||
#define INCREASE_FACTOR 4
|
||||
|
||||
/**
|
||||
* An bucket/chain within the hashmap
|
||||
*/
|
||||
typedef struct NcHashmapEntry {
|
||||
void *hash; /**<The key for this item */
|
||||
void *value; /**<Value for this item */
|
||||
struct NcHashmapEntry *next; /**<Next item in the chain */
|
||||
bool occ; /**<Whether this bucket is occupied */
|
||||
} NcHashmapEntry;
|
||||
|
||||
/**
|
||||
* A NcHashmap
|
||||
*/
|
||||
struct NcHashmap {
|
||||
int size; /**<Current size of the hashmap */
|
||||
int next_size; /**<Next size at which we need to resize */
|
||||
int n_buckets; /**<Current number of buckets */
|
||||
NcHashmapEntry *buckets; /**<Stores our bucket chains */
|
||||
|
||||
nc_hash_create_func hash; /**<Hash generation function */
|
||||
nc_hash_compare_func compare; /**<Key comparison function */
|
||||
nc_hash_free_func key_free; /**<Cleanup function for keys */
|
||||
nc_hash_free_func value_free; /**<Cleanup function for values */
|
||||
};
|
||||
|
||||
/**
|
||||
* Iteration object
|
||||
*/
|
||||
typedef struct _NcHashmapIter {
|
||||
int bucket; /**<Current bucket position */
|
||||
NcHashmap *map; /**<Associated NcHashmap */
|
||||
void *item; /**<Current item in this iteration */
|
||||
} _NcHashmapIter;
|
||||
|
||||
static void nc_hashmap_update_next_size(NcHashmap *self);
|
||||
static bool nc_hashmap_resize(NcHashmap *self);
|
||||
|
||||
static inline bool nc_hashmap_maybe_resize(NcHashmap *self)
|
||||
{
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
if (self->size >= self->next_size) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static NcHashmap *nc_hashmap_new_internal(nc_hash_create_func create, nc_hash_compare_func compare,
|
||||
nc_hash_free_func key_free, nc_hash_free_func value_free)
|
||||
{
|
||||
NcHashmap *map = NULL;
|
||||
NcHashmapEntry *buckets = NULL;
|
||||
|
||||
map = calloc(1, sizeof(NcHashmap));
|
||||
if (!map) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buckets = calloc(INITIAL_SIZE, sizeof(NcHashmapEntry));
|
||||
if (!buckets) {
|
||||
free(map);
|
||||
return NULL;
|
||||
}
|
||||
map->buckets = buckets;
|
||||
map->n_buckets = INITIAL_SIZE;
|
||||
map->hash = create ? create : nc_simple_hash;
|
||||
map->compare = compare ? compare : nc_simple_compare;
|
||||
map->key_free = key_free;
|
||||
map->value_free = value_free;
|
||||
map->size = 0;
|
||||
|
||||
nc_hashmap_update_next_size(map);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
NcHashmap *nc_hashmap_new(nc_hash_create_func create, nc_hash_compare_func compare)
|
||||
{
|
||||
return nc_hashmap_new_internal(create, compare, NULL, NULL);
|
||||
}
|
||||
|
||||
NcHashmap *nc_hashmap_new_full(nc_hash_create_func create, nc_hash_compare_func compare,
|
||||
nc_hash_free_func key_free, nc_hash_free_func value_free)
|
||||
{
|
||||
return nc_hashmap_new_internal(create, compare, key_free, value_free);
|
||||
}
|
||||
|
||||
static inline unsigned nc_hashmap_get_hash(NcHashmap *self, const void *key)
|
||||
{
|
||||
unsigned hash = self->hash(key);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static bool nc_hashmap_insert_bucket(NcHashmap *self, NcHashmapEntry *buckets, int n_buckets,
|
||||
unsigned hash, const void *key, void *value)
|
||||
{
|
||||
NcHashmapEntry *row = &(buckets[hash % n_buckets]);
|
||||
NcHashmapEntry *head = NULL;
|
||||
NcHashmapEntry *parent = head = row;
|
||||
bool can_replace = false;
|
||||
NcHashmapEntry *tomb = NULL;
|
||||
int ret = 1;
|
||||
|
||||
while (row) {
|
||||
if (!row->occ) {
|
||||
tomb = row;
|
||||
}
|
||||
parent = row;
|
||||
if (row->occ && row->hash == key) {
|
||||
if (self->compare(row->hash, key)) {
|
||||
can_replace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
row = row->next;
|
||||
}
|
||||
|
||||
if (can_replace) {
|
||||
/* Replace existing allocations. */
|
||||
if (self->value_free) {
|
||||
self->value_free(row->value);
|
||||
}
|
||||
if (self->key_free) {
|
||||
self->key_free(row->hash);
|
||||
}
|
||||
ret = 0;
|
||||
} else if (tomb) {
|
||||
row = tomb;
|
||||
}
|
||||
|
||||
if (!row) {
|
||||
row = calloc(1, sizeof(NcHashmapEntry));
|
||||
if (!row) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
row->hash = (void *)key;
|
||||
row->value = value;
|
||||
row->occ = true;
|
||||
if (parent != row && parent) {
|
||||
parent->next = row;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool nc_hashmap_put(NcHashmap *self, const void *key, void *value)
|
||||
{
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
int inc;
|
||||
|
||||
if (nc_hashmap_maybe_resize(self)) {
|
||||
if (!nc_hashmap_resize(self)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
unsigned hash = nc_hashmap_get_hash(self, key);
|
||||
inc = nc_hashmap_insert_bucket(self, self->buckets, self->n_buckets, hash, key, value);
|
||||
if (inc > 0) {
|
||||
self->size += inc;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static NcHashmapEntry *nc_hashmap_get_entry(NcHashmap *self, const void *key)
|
||||
{
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned hash = nc_hashmap_get_hash(self, key);
|
||||
NcHashmapEntry *row = &(self->buckets[hash % self->n_buckets]);
|
||||
|
||||
while (row) {
|
||||
if (self->compare(row->hash, key)) {
|
||||
return row;
|
||||
}
|
||||
row = row->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *nc_hashmap_get(NcHashmap *self, const void *key)
|
||||
{
|
||||
if (!self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NcHashmapEntry *row = nc_hashmap_get_entry(self, key);
|
||||
if (row) {
|
||||
return row->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool nc_hashmap_remove_internal(NcHashmap *self, const void *key, bool remove)
|
||||
{
|
||||
if (!self) {
|
||||
return false;
|
||||
}
|
||||
NcHashmapEntry *row = nc_hashmap_get_entry(self, key);
|
||||
|
||||
if (!row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
if (self->key_free) {
|
||||
self->key_free(row->hash);
|
||||
}
|
||||
if (self->value_free) {
|
||||
self->value_free(row->value);
|
||||
}
|
||||
}
|
||||
self->size -= 1;
|
||||
row->hash = NULL;
|
||||
row->value = NULL;
|
||||
row->occ = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nc_hashmap_steal(NcHashmap *self, const void *key)
|
||||
{
|
||||
return nc_hashmap_remove_internal(self, key, false);
|
||||
}
|
||||
|
||||
bool nc_hashmap_remove(NcHashmap *self, const void *key)
|
||||
{
|
||||
return nc_hashmap_remove_internal(self, key, true);
|
||||
}
|
||||
|
||||
bool nc_hashmap_contains(NcHashmap *self, const void *key)
|
||||
{
|
||||
return (nc_hashmap_get(self, key)) != NULL;
|
||||
}
|
||||
|
||||
static inline void nc_hashmap_free_bucket(NcHashmap *self, NcHashmapEntry *bucket, bool nuke)
|
||||
{
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
NcHashmapEntry *tmp = bucket;
|
||||
NcHashmapEntry *bk = bucket;
|
||||
NcHashmapEntry *root = bucket;
|
||||
|
||||
while (tmp) {
|
||||
bk = NULL;
|
||||
if (tmp->next) {
|
||||
bk = tmp->next;
|
||||
}
|
||||
|
||||
if (nuke && tmp->occ) {
|
||||
if (self->key_free) {
|
||||
self->key_free(tmp->hash);
|
||||
}
|
||||
if (self->value_free) {
|
||||
self->value_free(tmp->value);
|
||||
}
|
||||
}
|
||||
if (tmp != root) {
|
||||
free(tmp);
|
||||
}
|
||||
tmp = bk;
|
||||
}
|
||||
}
|
||||
|
||||
void nc_hashmap_free(NcHashmap *self)
|
||||
{
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < self->n_buckets; i++) {
|
||||
NcHashmapEntry *row = &(self->buckets[i]);
|
||||
nc_hashmap_free_bucket(self, row, true);
|
||||
}
|
||||
if (self->buckets) {
|
||||
free(self->buckets);
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
static void nc_hashmap_update_next_size(NcHashmap *self)
|
||||
{
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
self->next_size = (int)(self->n_buckets * FULL_FACTOR);
|
||||
}
|
||||
|
||||
int nc_hashmap_size(NcHashmap *self)
|
||||
{
|
||||
if (!self) {
|
||||
return -1;
|
||||
}
|
||||
return self->size;
|
||||
}
|
||||
|
||||
static bool nc_hashmap_resize(NcHashmap *self)
|
||||
{
|
||||
if (!self || !self->buckets) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NcHashmapEntry *old_buckets = self->buckets;
|
||||
NcHashmapEntry *new_buckets = NULL;
|
||||
NcHashmapEntry *entry = NULL;
|
||||
int incr;
|
||||
|
||||
int old_size, new_size;
|
||||
int items = 0;
|
||||
|
||||
new_size = old_size = self->n_buckets;
|
||||
new_size *= INCREASE_FACTOR;
|
||||
|
||||
new_buckets = calloc(new_size, sizeof(NcHashmapEntry));
|
||||
if (!new_buckets) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < old_size; i++) {
|
||||
entry = &(old_buckets[i]);
|
||||
while (entry) {
|
||||
if (entry->occ) {
|
||||
unsigned hash = nc_hashmap_get_hash(self, entry->hash);
|
||||
if ((incr = nc_hashmap_insert_bucket(self,
|
||||
new_buckets,
|
||||
new_size,
|
||||
hash,
|
||||
entry->hash,
|
||||
entry->value)) > 0) {
|
||||
items += incr;
|
||||
} else {
|
||||
/* Likely a memory issue */
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
/* Successfully resized - do this separately because we need to
|
||||
* gaurantee old data is preserved */
|
||||
for (int i = 0; i < old_size; i++) {
|
||||
nc_hashmap_free_bucket(self, &(old_buckets[i]), false);
|
||||
}
|
||||
|
||||
free(old_buckets);
|
||||
self->n_buckets = new_size;
|
||||
self->size = items;
|
||||
self->buckets = new_buckets;
|
||||
|
||||
nc_hashmap_update_next_size(self);
|
||||
return true;
|
||||
|
||||
failure:
|
||||
for (int i = 0; i < new_size; i++) {
|
||||
nc_hashmap_free_bucket(self, &(new_buckets[i]), true);
|
||||
}
|
||||
free(new_buckets);
|
||||
return false;
|
||||
}
|
||||
|
||||
void nc_hashmap_iter_init(NcHashmap *map, NcHashmapIter *citer)
|
||||
{
|
||||
_NcHashmapIter *iter = NULL;
|
||||
if (!map || !citer) {
|
||||
return;
|
||||
}
|
||||
iter = (_NcHashmapIter *)citer;
|
||||
_NcHashmapIter it = {
|
||||
.bucket = -1, .map = map, .item = NULL,
|
||||
};
|
||||
*iter = it;
|
||||
}
|
||||
|
||||
bool nc_hashmap_iter_next(NcHashmapIter *citer, void **key, void **value)
|
||||
{
|
||||
_NcHashmapIter *iter = NULL;
|
||||
NcHashmapEntry *item = NULL;
|
||||
NcHashmap *map = NULL;
|
||||
int n_buckets = 0;
|
||||
|
||||
if (!citer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
iter = (_NcHashmapIter *)citer;
|
||||
map = iter->map;
|
||||
if (!map) {
|
||||
return false;
|
||||
}
|
||||
n_buckets = map->n_buckets;
|
||||
item = iter->item;
|
||||
|
||||
for (;;) {
|
||||
if (iter->bucket >= n_buckets) {
|
||||
if (item && !item->next) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!item) {
|
||||
iter->bucket++;
|
||||
if (iter->bucket > n_buckets - 1) {
|
||||
return false;
|
||||
}
|
||||
item = &(map->buckets[iter->bucket]);
|
||||
}
|
||||
if (item && item->occ) {
|
||||
goto success;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
return false;
|
||||
|
||||
success:
|
||||
iter->item = item->next;
|
||||
if (key) {
|
||||
*key = item->hash;
|
||||
}
|
||||
if (value) {
|
||||
*value = item->value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* libnica is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This is a chained Hashmap implementation. It focuses on being clean
|
||||
* and efficient, and is comparable (at -O2) to open addressing hashmaps
|
||||
* up until around 105,000 elements, where open addressing will begin
|
||||
* to come out in front. At 1 million elements, open addressing is a clear
|
||||
* winner, however currently we only need a maximum of 70k elements in
|
||||
* our implementation.
|
||||
*
|
||||
* Given the memory required to even begin to deal with 1 million elements,
|
||||
* it becomes very questionable whether a hashmap should have even been
|
||||
* used in the first place (mmap'd db?)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* Convert between uint and void* */
|
||||
#define NC_HASH_KEY(x) ((void *)((uintptr_t)(x)))
|
||||
#define NC_HASH_VALUE(x) NC_HASH_KEY(x)
|
||||
#define NC_UNHASH_KEY(x) ((unsigned int)((uintptr_t)(x)))
|
||||
#define NC_UNHASH_VALUE(x) NC_UNHASH_KEY(x)
|
||||
|
||||
typedef struct NcHashmap NcHashmap;
|
||||
|
||||
/**
|
||||
* Iteration object
|
||||
*/
|
||||
typedef struct NcHashmapIter {
|
||||
int n0;
|
||||
void *n1;
|
||||
void *n2;
|
||||
} NcHashmapIter;
|
||||
|
||||
/**
|
||||
* Hash comparison function definition
|
||||
*
|
||||
* @param l First value to compare
|
||||
* @param r Second value to compare
|
||||
*
|
||||
* @return true if l and r both match, otherwise false
|
||||
*/
|
||||
typedef bool (*nc_hash_compare_func)(const void *l, const void *r);
|
||||
|
||||
/**
|
||||
* Hash creation function definition
|
||||
*
|
||||
* @param key Key to generate a hash for
|
||||
*
|
||||
* @return an unsigned integer hash result
|
||||
*/
|
||||
typedef unsigned (*nc_hash_create_func)(const void *key);
|
||||
|
||||
/**
|
||||
* Callback definition to free keys and values
|
||||
*
|
||||
* @param p Single-depth pointer to either a key or value that should be freed
|
||||
*/
|
||||
typedef void (*nc_hash_free_func)(void *p);
|
||||
|
||||
/**
|
||||
* Default hash/comparison functions
|
||||
*
|
||||
* @note These are only used for comparison of *keys*, not values. Unless
|
||||
* explicitly using string keys, you should most likely stick with the default
|
||||
* nc_simple_hash and nc_simple_compare functions
|
||||
*/
|
||||
|
||||
/* Default string hash */
|
||||
static inline unsigned nc_string_hash(const void *key)
|
||||
{
|
||||
unsigned hash = 5381;
|
||||
const signed char *c;
|
||||
|
||||
/* DJB's hash function */
|
||||
for (c = key; *c != '\0'; c++) {
|
||||
hash = (hash << 5) + hash + (unsigned)*c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial pointer->uint hash
|
||||
*/
|
||||
static inline unsigned nc_simple_hash(const void *source)
|
||||
{
|
||||
return NC_UNHASH_KEY(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison of string keys
|
||||
*/
|
||||
static inline bool nc_string_compare(const void *l, const void *r)
|
||||
{
|
||||
if (!l || !r) {
|
||||
return false;
|
||||
}
|
||||
return (strcmp(l, r) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial pointer comparison
|
||||
*/
|
||||
static inline bool nc_simple_compare(const void *l, const void *r)
|
||||
{
|
||||
return (l == r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NcHashmap
|
||||
*
|
||||
* @param hash Hash creation function
|
||||
* @param compare Key comparison function
|
||||
*
|
||||
* @return A newly allocated NcHashmap
|
||||
*/
|
||||
NcHashmap *nc_hashmap_new(nc_hash_create_func hash, nc_hash_compare_func compare);
|
||||
|
||||
/**
|
||||
* Create a new NcHashmap with cleanup functions
|
||||
*
|
||||
* @param hash Hash creation function
|
||||
* @param compare Key comparison function
|
||||
* @param key_free Function to free keys when removed/destroyed
|
||||
* @param value_free Function to free values when removed/destroyed
|
||||
*
|
||||
* @return A newly allocated NcHashmap
|
||||
*/
|
||||
NcHashmap *nc_hashmap_new_full(nc_hash_create_func hash, nc_hash_compare_func compare,
|
||||
nc_hash_free_func key_free, nc_hash_free_func value_free);
|
||||
|
||||
/**
|
||||
* Store a key/value pair in the hashmap
|
||||
*
|
||||
* @note This will displace duplicate keys, and may free both the key
|
||||
* and value if key_free and value_free are non null
|
||||
*
|
||||
* @param key Key to store in the hashmap
|
||||
* @param value Value to be associated with the key
|
||||
*
|
||||
* @return true if the operation succeeded.
|
||||
*/
|
||||
bool nc_hashmap_put(NcHashmap *map, const void *key, void *value);
|
||||
|
||||
/**
|
||||
* Get the value associated with the unique key
|
||||
*
|
||||
* @param key Unique key to obtain a value for
|
||||
* @return The associated value if it exists, otherwise NULL
|
||||
*/
|
||||
void *nc_hashmap_get(NcHashmap *map, const void *key);
|
||||
|
||||
/**
|
||||
* Determine if the key has an associated value in the NcHashmap
|
||||
*
|
||||
* @param key Unique key to check value for
|
||||
* @return True if the key exists in the hashmap
|
||||
*/
|
||||
bool nc_hashmap_contains(NcHashmap *self, const void *key);
|
||||
|
||||
/**
|
||||
* Free the given NcHashmap, and all keys/values if appropriate
|
||||
*/
|
||||
void nc_hashmap_free(NcHashmap *map);
|
||||
|
||||
/**
|
||||
* Remove the value and key identified by key.
|
||||
*
|
||||
* @note If key_free or value_free are non-NULL, they will be invoked
|
||||
* for both the key and value being removed
|
||||
*
|
||||
* @param key The unique key to remove
|
||||
* @return true if the key/value pair were removed
|
||||
*/
|
||||
bool nc_hashmap_remove(NcHashmap *map, const void *key);
|
||||
|
||||
/**
|
||||
* Remove the value and key identified by key without freeing them
|
||||
*
|
||||
* @return true if the key/value pair were stolen
|
||||
*/
|
||||
bool nc_hashmap_steal(NcHashmap *map, const void *key);
|
||||
|
||||
/**
|
||||
* Return the current size of the hashmap
|
||||
*
|
||||
* @return size of the current hashmap (element count)
|
||||
*/
|
||||
int nc_hashmap_size(NcHashmap *map);
|
||||
|
||||
/**
|
||||
* Initialise a NcHashmapIter for iteration purposes
|
||||
*
|
||||
* @note The iter *must* be re-inited to re-use, or if it becomes
|
||||
* exhausted from a previous iteration run
|
||||
*
|
||||
* @param iter pointer to a NcHashmapIter
|
||||
*/
|
||||
void nc_hashmap_iter_init(NcHashmap *map, NcHashmapIter *iter);
|
||||
|
||||
/**
|
||||
* Iterate every key/value pair in the hashmap
|
||||
*
|
||||
* @param iter A correctly initialised NcHashmapIter
|
||||
* @param key Pointers to store the key in, may be NULL to skip
|
||||
* @param value Pointer to store the value in, may be NULL to skip
|
||||
*
|
||||
* @return true if it's possible to iterate
|
||||
*/
|
||||
bool nc_hashmap_iter_next(NcHashmapIter *iter, void **key, void **value);
|
||||
|
||||
DEF_AUTOFREE(NcHashmap, nc_hashmap_free)
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -1,341 +0,0 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* libnica is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "inifile.h"
|
||||
|
||||
/**
|
||||
* Mapping of @NcIniError to static strings
|
||||
*/
|
||||
static const char *_errors[] = {[NC_INI_ERROR_FILE] = "",
|
||||
[NC_INI_ERROR_EMPTY_KEY] = "Encountered empty key",
|
||||
[NC_INI_ERROR_NOT_CLOSED] = "Expected closing \']\' for section",
|
||||
[NC_INI_ERROR_NO_SECTION] =
|
||||
"Encountered key=value mapping without a valid section",
|
||||
[NC_INI_ERROR_INVALID_LINE] = "Expected key=value notation" };
|
||||
|
||||
const char *nc_ini_error(NcIniError error)
|
||||
{
|
||||
int j = abs(error);
|
||||
if (j < NC_INI_ERROR_FILE || j >= NC_INI_ERROR_MAX) {
|
||||
return "[Unknown Error]";
|
||||
}
|
||||
return _errors[j];
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip leading whitespace from string (left)
|
||||
*/
|
||||
static char *lstrip(char *str, size_t len, size_t *out_len)
|
||||
{
|
||||
size_t skip_len = 0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] == ' ' || str[i] == '\t') {
|
||||
++skip_len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*out_len = len - skip_len;
|
||||
if (skip_len > 0) {
|
||||
char *c = strdup(str + skip_len);
|
||||
free(str);
|
||||
return c;
|
||||
}
|
||||
return str + skip_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip trailing whitespace from string (right)
|
||||
*/
|
||||
static char *rstrip(char *str, size_t len, size_t *out_len)
|
||||
{
|
||||
size_t skip_len = 0;
|
||||
|
||||
for (int i = len; i > 0; i--) {
|
||||
if (str[i] == ' ' || str[i] == '\t') {
|
||||
++skip_len;
|
||||
continue;
|
||||
} else if (str[i] == '\0') {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*out_len = len - skip_len;
|
||||
if (len == skip_len) {
|
||||
return str;
|
||||
}
|
||||
str[(len - skip_len)] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chew both ends of a null terminated string of whitespace
|
||||
* If the left side is whitespace padded, this will always result
|
||||
* in a new allocation due to fast-forwarding the pointer. Keep
|
||||
* this in mind.
|
||||
*/
|
||||
static char *string_chew_terminated(char *inp)
|
||||
{
|
||||
int skip_offset = 0;
|
||||
int len = 0;
|
||||
int end_len = 0;
|
||||
bool count = true;
|
||||
|
||||
if (!inp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (char *c = inp; *c; c++) {
|
||||
if (count && (*c == ' ' || *c == '\t')) {
|
||||
++skip_offset;
|
||||
continue;
|
||||
} else {
|
||||
count = false;
|
||||
}
|
||||
++len;
|
||||
}
|
||||
for (int i = len; i > skip_offset; i--) {
|
||||
if (inp[i] == ' ' || inp[i] == '\t') {
|
||||
++end_len;
|
||||
continue;
|
||||
} else if (inp[i] == '\0') {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (end_len > 0) {
|
||||
inp[(len - end_len)] = '\0';
|
||||
}
|
||||
if (skip_offset > 0) {
|
||||
char *c = strdup(inp + skip_offset);
|
||||
free(inp);
|
||||
return c;
|
||||
}
|
||||
return inp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Munch both ends of the string
|
||||
*/
|
||||
static char *string_strip(char *str, size_t len, size_t *out_len)
|
||||
{
|
||||
size_t mylen = len;
|
||||
|
||||
char *c = lstrip(str, len, &mylen);
|
||||
c = rstrip(c, mylen, &mylen);
|
||||
if (out_len) {
|
||||
*out_len = mylen;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
NcHashmap *nc_ini_file_parse(const char *path)
|
||||
{
|
||||
NcHashmap *ret = NULL;
|
||||
int error_line = 0;
|
||||
int r = 0;
|
||||
|
||||
r = nc_ini_file_parse_full(path, &ret, &error_line);
|
||||
if (r != 0) {
|
||||
if (abs(r) == NC_INI_ERROR_FILE) {
|
||||
fprintf(stderr, "[inifile] %s: %s\n", strerror(errno), path);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"[inifile] %s [L%d]: %s\n",
|
||||
nc_ini_error(r),
|
||||
error_line,
|
||||
path);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nc_ini_file_parse_full(const char *path, NcHashmap **out_map, int *error_line_number)
|
||||
{
|
||||
autofree(FILE) *file = NULL;
|
||||
char *buf = NULL;
|
||||
ssize_t r = 0;
|
||||
size_t sn = 0;
|
||||
int line_count = 1;
|
||||
char *current_section = NULL;
|
||||
NcHashmap *root_map = NULL;
|
||||
NcHashmap *section_map = NULL;
|
||||
bool failed = false;
|
||||
int err_ret = 0;
|
||||
|
||||
file = fopen(path, "r");
|
||||
if (!file) {
|
||||
return -(NC_INI_ERROR_FILE);
|
||||
}
|
||||
|
||||
if (!out_map) {
|
||||
fprintf(stderr, "nc_ini_file_parse_full(): NcHashmap pointer invalid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
root_map = nc_hashmap_new_full(nc_string_hash,
|
||||
nc_string_compare,
|
||||
free,
|
||||
(nc_hash_free_func)nc_hashmap_free);
|
||||
|
||||
while ((r = getline(&buf, &sn, file)) != -1) {
|
||||
char *ch = NULL;
|
||||
size_t str_len = r;
|
||||
|
||||
/* Fix newline */
|
||||
if (buf[r - 1] == '\n') {
|
||||
buf[r - 1] = '\0';
|
||||
--r;
|
||||
}
|
||||
str_len = r;
|
||||
|
||||
buf = string_strip(buf, r, &str_len);
|
||||
/* Empty lines are fine */
|
||||
if (streq(buf, "")) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (buf[0] == '[') {
|
||||
/* Validate section start */
|
||||
if (buf[str_len - 1] != ']') {
|
||||
/* Throw error */
|
||||
err_ret = NC_INI_ERROR_NOT_CLOSED;
|
||||
goto fail;
|
||||
}
|
||||
/* Grab the section name, and "close" last section */
|
||||
buf[str_len - 1] = '\0';
|
||||
if (current_section) {
|
||||
free(current_section);
|
||||
}
|
||||
current_section = strdup(buf + 1);
|
||||
section_map = nc_hashmap_get(root_map, current_section);
|
||||
if (!section_map) {
|
||||
/* Create a new section dynamically */
|
||||
section_map = nc_hashmap_new_full(nc_string_hash,
|
||||
nc_string_compare,
|
||||
free,
|
||||
free);
|
||||
nc_hashmap_put(root_map, strdup(current_section), section_map);
|
||||
}
|
||||
goto next;
|
||||
} else if (buf[0] == '#' || buf[0] == ';') {
|
||||
/* Skip comment */
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Look for key = value */
|
||||
ch = strchr(buf, '=');
|
||||
if (!ch) {
|
||||
/* Throw error */
|
||||
err_ret = NC_INI_ERROR_INVALID_LINE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Can't have sectionless k->v */
|
||||
if (!current_section) {
|
||||
err_ret = NC_INI_ERROR_NO_SECTION;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int offset = ch - buf;
|
||||
|
||||
/* Grab the key->value from this assignment line */
|
||||
char *value = strdup((buf + offset) + 1);
|
||||
buf[offset] = '\0';
|
||||
char *key = strdup(buf);
|
||||
key = string_chew_terminated(key);
|
||||
value = string_chew_terminated(value);
|
||||
|
||||
if (streq(key, "")) {
|
||||
err_ret = NC_INI_ERROR_EMPTY_KEY;
|
||||
free(key);
|
||||
free(value);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Ensure a section mapping exists */
|
||||
section_map = nc_hashmap_get(root_map, current_section);
|
||||
if (!section_map) {
|
||||
err_ret = 1;
|
||||
fprintf(stderr,
|
||||
"[inifile] Fatal! No section map for named "
|
||||
"section: %s\n",
|
||||
current_section);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Insert these guys into the map */
|
||||
if (!nc_hashmap_put(section_map, key, value)) {
|
||||
err_ret = 1;
|
||||
fprintf(stderr, "[inifile] Fatal! Out of memory\n");
|
||||
abort();
|
||||
}
|
||||
/* Progression + cleanup */
|
||||
next:
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
++line_count;
|
||||
sn = 0;
|
||||
continue;
|
||||
/* Parsing error, bail */
|
||||
fail:
|
||||
failed = true;
|
||||
if (error_line_number) {
|
||||
*error_line_number = line_count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
if (current_section) {
|
||||
free(current_section);
|
||||
current_section = NULL;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
if (root_map) {
|
||||
nc_hashmap_free(root_map);
|
||||
}
|
||||
return -(err_ret);
|
||||
}
|
||||
*out_map = root_map;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* libnica is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "util.h"
|
||||
|
||||
/**
|
||||
* The Nica INI Parser focuses on simplicity and ease of use, therefore it
|
||||
* currently only supports a read-only parse operation.
|
||||
*
|
||||
* The parse functions are used to return a _root_ @NcHashmap which contains
|
||||
* name to section mappings. Each section is in turn an @NcHashmap with string
|
||||
* to string mappings.
|
||||
*
|
||||
* Consider the following example:
|
||||
*
|
||||
* [Person]
|
||||
* alive = true
|
||||
* ; This person is alive
|
||||
*
|
||||
* The returned @NcHashmap will contain the key "Person", which corresponds to
|
||||
* another @NcHashmap. This @NcHashmap will contain the key "alive", which has
|
||||
* the value "true". Therefore we can access this variable using the @NcHashmap
|
||||
* API:
|
||||
*
|
||||
* char *alive = nc_hashmap_get(nc_hashmap_get(ini, "Person"), "alive");
|
||||
*
|
||||
* Conversely, we can use the API to determine whether a section or key is set:
|
||||
*
|
||||
* if (nc_hashmap_contains(ini, "Person"))
|
||||
*
|
||||
* As @NcHashmap returns NULL in nc_hashmap_get, you can happily pass NULL
|
||||
* keys, allowing quick key fetches without checking if the section exists.
|
||||
*
|
||||
* In our INI file, lines beginning with ";" or "#" are considered as comments
|
||||
* and are not processed. A line following the "key = value" notation is an
|
||||
* _assignment_. "[Section]" is considered to be a section in the INI file, and
|
||||
* all INI files must have at least one section.
|
||||
*
|
||||
* We do allow duplication section definitions, by following a merge policy. If
|
||||
* a key is redefined then the original key->value mapping is freed and the new
|
||||
* key->value mapping is inserted.
|
||||
*
|
||||
* The parser will return a correctly configured @NcHashmap, the only cleanup
|
||||
* required is to call nc_hashmap_free on it. Alternatively, use the autofree
|
||||
* helper, for a RAII approach:
|
||||
*
|
||||
* autofree(NcHashmap) *map = nc_ini_file_parse("myfile.ini");
|
||||
*/
|
||||
|
||||
/**
|
||||
* Errors that are reported when parsing an ini file
|
||||
*/
|
||||
typedef enum {
|
||||
NC_INI_ERROR_MIN = 0,
|
||||
NC_INI_ERROR_FILE, /**< File based error, check strerror(errno) */
|
||||
NC_INI_ERROR_EMPTY_KEY, /**< Empty key in an assignment line */
|
||||
NC_INI_ERROR_NOT_CLOSED, /**< Encountered section start that wasn't closed with a ']' */
|
||||
NC_INI_ERROR_NO_SECTION, /**< Key assignment with no defined sections */
|
||||
NC_INI_ERROR_INVALID_LINE, /**< Encountered an invalid line (syntax) */
|
||||
NC_INI_ERROR_MAX
|
||||
} NcIniError;
|
||||
|
||||
/**
|
||||
* Convenience wrapper for nc_ini_file_parse_full, reports errors to stderrr
|
||||
* and returns an NcHashmap if the parsing succeeded
|
||||
*/
|
||||
NcHashmap *nc_ini_file_parse(const char *path);
|
||||
|
||||
/**
|
||||
* Parse an INI file into a hash of hashes.
|
||||
*
|
||||
* @param path Path on the filesystem to parse, must be in INI syntax.
|
||||
* @param out_map Pointer to store the resulting root NcHashmap in
|
||||
* @param error_line_number If not null, then the erronous line number is
|
||||
* stored.
|
||||
*
|
||||
* @return 0 if the call was succesful, or a negative integer. See nc_ini_error
|
||||
*/
|
||||
int nc_ini_file_parse_full(const char *path, NcHashmap **out_map, int *error_line_number);
|
||||
|
||||
/**
|
||||
* Return a string representation for a given @NcIniError
|
||||
*
|
||||
* @param error Valid NcIniError code
|
||||
* @return a static string owned by the implementation
|
||||
*/
|
||||
const char *nc_ini_error(NcIniError error);
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* libnica is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEF_AUTOFREE(N, C) \
|
||||
static inline void _autofree_func_##N(void *p) \
|
||||
{ \
|
||||
if (p && *(N **)p) { \
|
||||
C(*(N **)p); \
|
||||
(*(void **)p) = NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define autofree(N) __attribute__((cleanup(_autofree_func_##N))) N
|
||||
|
||||
/**
|
||||
* Dump any leaked file descriptors
|
||||
*/
|
||||
void nc_dump_file_descriptor_leaks(void);
|
||||
|
||||
#define streq(x, y) strcmp(x, y) == 0 ? true : false
|
||||
|
||||
DEF_AUTOFREE(char, free)
|
||||
DEF_AUTOFREE(FILE, fclose)
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <libgen.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../common/files.h"
|
||||
#include "../common/log.h"
|
||||
#include "nica/util.h"
|
||||
|
||||
#include "profile.h"
|
||||
#include "redirect.h"
|
||||
|
||||
#define _STRINGIFY(x) #x
|
||||
|
||||
#define SYMBOL_BINDING(l, x) \
|
||||
{ \
|
||||
.handle = &lsi_table.handles.l, .name = _STRINGIFY(x), \
|
||||
.func = (void **)(&lsi_table.x), .func_size = sizeof(lsi_table.x) \
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we've initialised yet or not.
|
||||
*/
|
||||
static volatile bool lsi_init = false;
|
||||
|
||||
/**
|
||||
* Whether we should actually perform overrides
|
||||
* This is determined by the process name
|
||||
*/
|
||||
static volatile bool lsi_override = false;
|
||||
|
||||
/**
|
||||
* Handle definitions
|
||||
*/
|
||||
typedef int (*lsi_open_file)(const char *p, int flags, mode_t mode);
|
||||
|
||||
typedef FILE *(*lsi_fopen64_file)(const char *p, const char *modes);
|
||||
|
||||
/**
|
||||
* Known profiles
|
||||
*/
|
||||
static lsi_profile_generator_func generators[] = {
|
||||
&lsi_redirect_profile_new_ark,
|
||||
&lsi_redirect_profile_new_project_highrise,
|
||||
};
|
||||
|
||||
/**
|
||||
* Global storage of handles for nicer organisation.
|
||||
*/
|
||||
typedef struct LsiRedirectTable {
|
||||
lsi_open_file open;
|
||||
lsi_fopen64_file fopen64;
|
||||
|
||||
/* Allow future handle opens.. */
|
||||
struct {
|
||||
void *libc;
|
||||
} handles;
|
||||
} LsiRedirectTable;
|
||||
|
||||
/**
|
||||
* Easy mapping to make it quick and easy to add new function overrides
|
||||
*/
|
||||
typedef struct LsiSymbolBinding {
|
||||
void **handle;
|
||||
char *name;
|
||||
void **func;
|
||||
size_t func_size;
|
||||
} LsiSymbolBinding;
|
||||
|
||||
/**
|
||||
* Our redirect instance, stack only.
|
||||
*/
|
||||
static LsiRedirectTable lsi_table = { 0 };
|
||||
|
||||
/**
|
||||
* Contains all of our replacement rules.
|
||||
*/
|
||||
static LsiRedirectProfile *lsi_profile = NULL;
|
||||
|
||||
/**
|
||||
* Our current set of libc bindings. This sets up the LsiRedirectTable with
|
||||
* all of our needed dlsym() functions from libc.so.6.
|
||||
*/
|
||||
static LsiSymbolBinding lsi_libc_bindings[] = {
|
||||
SYMBOL_BINDING(libc, open),
|
||||
SYMBOL_BINDING(libc, fopen64),
|
||||
};
|
||||
|
||||
/**
|
||||
* We'll only perform teardown code if the process doesn't `abort()` or `_exit()`
|
||||
*/
|
||||
__attribute__((destructor)) static void lsi_redirect_shutdown(void)
|
||||
{
|
||||
if (lsi_profile) {
|
||||
lsi_redirect_profile_free(lsi_profile);
|
||||
lsi_profile = NULL;
|
||||
}
|
||||
|
||||
if (!lsi_init) {
|
||||
return;
|
||||
}
|
||||
lsi_init = false;
|
||||
|
||||
if (lsi_table.handles.libc) {
|
||||
dlclose(lsi_table.handles.libc);
|
||||
lsi_table.handles.libc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to perform the symbol binding
|
||||
*/
|
||||
static bool lsi_redirect_bind_function(void *handle, const char *name, void **out_func,
|
||||
size_t func_size)
|
||||
{
|
||||
void *symbol_lookup = NULL;
|
||||
char *dl_error = NULL;
|
||||
|
||||
/* Safely look up the symbol */
|
||||
symbol_lookup = dlsym(handle, name);
|
||||
dl_error = dlerror();
|
||||
if (dl_error || !symbol_lookup) {
|
||||
fprintf(stderr, "Failed to bind '%s': %s\n", name, dl_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Have the symbol correctly, copy it to make it usable */
|
||||
memcpy(out_func, &symbol_lookup, func_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for setting up the vfunc redirect table so that we're able to
|
||||
* get `open` and such working before we've hit the constructor, and ensure
|
||||
* we only init once.
|
||||
*/
|
||||
static void lsi_redirect_init_tables(void)
|
||||
{
|
||||
if (lsi_init) {
|
||||
return;
|
||||
}
|
||||
|
||||
lsi_init = true;
|
||||
|
||||
/* Try to explicitly open libc. We can't safely rely on RTLD_NEXT
|
||||
* as we might be dealing with a strange link order
|
||||
*/
|
||||
lsi_table.handles.libc = dlopen("libc.so.6", RTLD_LAZY);
|
||||
if (!lsi_table.handles.libc) {
|
||||
fprintf(stderr, "Unable to grab libc.so.6 handle: %s\n", dlerror());
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Hook up all necessary symbol binding */
|
||||
for (size_t i = 0; i < ARRAY_SIZE(lsi_libc_bindings); i++) {
|
||||
LsiSymbolBinding *binding = &lsi_libc_bindings[i];
|
||||
if (!lsi_redirect_bind_function(*(binding->handle),
|
||||
binding->name,
|
||||
binding->func,
|
||||
binding->func_size)) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* We might not get an unload, so chain onto atexit */
|
||||
atexit(lsi_redirect_shutdown);
|
||||
return;
|
||||
|
||||
failed:
|
||||
/* Pretty damn fatal. */
|
||||
lsi_redirect_shutdown();
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point into this redirect module.
|
||||
*
|
||||
* We'll check the process name and determine if we're interested in installing
|
||||
* some redirect hooks into this library.
|
||||
* Otherwise we'll continue to operate in a pass-through mode
|
||||
*/
|
||||
__attribute__((constructor)) static void lsi_redirect_init(void)
|
||||
{
|
||||
/* Ensure we're open. */
|
||||
lsi_redirect_init_tables();
|
||||
autofree(char) *process_name = NULL;
|
||||
char **paths = NULL;
|
||||
char **orig = NULL;
|
||||
|
||||
/* Absolute path to the process for fine-grained matching */
|
||||
process_name = lsi_get_process_name();
|
||||
|
||||
if (!process_name) {
|
||||
fputs("Out of memory!\n", stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Grab the stam installation directories */
|
||||
orig = paths = lsi_get_steam_paths();
|
||||
|
||||
/* For each path try to form a valid profile for the process name and Steam directory */
|
||||
while (*paths) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(generators); i++) {
|
||||
lsi_profile = generators[i](process_name, *paths);
|
||||
if (lsi_profile) {
|
||||
goto use_profile;
|
||||
}
|
||||
}
|
||||
++paths;
|
||||
}
|
||||
|
||||
use_profile:
|
||||
/* Rewind path set */
|
||||
paths = orig;
|
||||
|
||||
if (!lsi_profile) {
|
||||
goto clean_array;
|
||||
}
|
||||
|
||||
lsi_override = true;
|
||||
lsi_log_debug("Enable lsi_redirect for '%s'", lsi_profile->name);
|
||||
|
||||
clean_array:
|
||||
|
||||
/* Free them again */
|
||||
if (paths) {
|
||||
while (*paths) {
|
||||
free(*paths);
|
||||
++paths;
|
||||
}
|
||||
free(orig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a redirect path from the table if it exists, otherwise return NULL
|
||||
*/
|
||||
static char *lsi_get_redirect_path(const char *syscall_id, LsiRedirectOperation op, const char *p)
|
||||
{
|
||||
autofree(char) *path = NULL;
|
||||
LsiRedirect *redirect = NULL;
|
||||
|
||||
/* Get the absolute path here */
|
||||
path = realpath(p, NULL);
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find a valid replacement */
|
||||
for (redirect = lsi_profile->op_table[op]; redirect; redirect = redirect->next) {
|
||||
/* Currently we only known path replacements */
|
||||
if (redirect->type != LSI_REDIRECT_PATH) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(redirect->path_source, path) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!lsi_file_exists(redirect->path_target)) {
|
||||
lsi_log_warn("Replacement path does not exist: %s", redirect->path_target);
|
||||
return NULL;
|
||||
}
|
||||
lsi_log_info("%s(): Replaced '%s' with '%s'",
|
||||
syscall_id,
|
||||
path,
|
||||
redirect->path_target);
|
||||
return strdup(redirect->path_target);
|
||||
}
|
||||
|
||||
/* Got nothin' */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_nica_public_ int open(const char *p, int flags, ...)
|
||||
{
|
||||
va_list va;
|
||||
mode_t mode;
|
||||
LsiRedirectOperation op = LSI_OPERATION_OPEN;
|
||||
autofree(char) *replacement = NULL;
|
||||
|
||||
/* Must ensure we're **really** initialised, as we might see open happen
|
||||
* before the constructor..
|
||||
*/
|
||||
lsi_redirect_init_tables();
|
||||
|
||||
/* Grab the mode_t */
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, mode_t);
|
||||
va_end(va);
|
||||
|
||||
/* Not interested in this guy apparently */
|
||||
if (!lsi_override) {
|
||||
return lsi_table.open(p, flags, mode);
|
||||
}
|
||||
|
||||
replacement = lsi_get_redirect_path("open", op, p);
|
||||
if (!replacement) {
|
||||
return lsi_table.open(p, flags, mode);
|
||||
}
|
||||
return lsi_table.open(replacement, flags, mode);
|
||||
}
|
||||
|
||||
_nica_public_ FILE *fopen64(const char *p, const char *modes)
|
||||
{
|
||||
LsiRedirectOperation op = LSI_OPERATION_OPEN;
|
||||
autofree(char) *replacement = NULL;
|
||||
|
||||
/* Must ensure we're **really** initialised, as we might see open happen
|
||||
* before the constructor..
|
||||
*/
|
||||
lsi_redirect_init_tables();
|
||||
|
||||
/* Not interested in this guy apparently */
|
||||
if (!lsi_override) {
|
||||
return lsi_table.fopen64(p, modes);
|
||||
}
|
||||
|
||||
replacement = lsi_get_redirect_path("fopen64", op, p);
|
||||
if (!replacement) {
|
||||
return lsi_table.fopen64(p, modes);
|
||||
}
|
||||
return lsi_table.fopen64(replacement, modes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,29 @@
|
||||
# Only build libredirect if told to!
|
||||
|
||||
if with_libredirect == true
|
||||
|
||||
# Might not need libdl for alt libcs
|
||||
libdl = meson.get_compiler('c').find_library('dl', required : false)
|
||||
|
||||
redirect_sources = [
|
||||
'main.c',
|
||||
'profile.c',
|
||||
'profiles/ark.c',
|
||||
'profiles/project_highrise.c',
|
||||
]
|
||||
|
||||
sym_map = join_paths(meson.current_source_dir(), 'sym.map')
|
||||
|
||||
main_redirect = shared_library(
|
||||
'lsi-redirect',
|
||||
sources: redirect_sources,
|
||||
c_args: ['-fvisibility=hidden'],
|
||||
link_args: ['-Wl,--version-script=@0@'.format(sym_map)],
|
||||
include_directories: nica_includes,
|
||||
dependencies: [
|
||||
libdl,
|
||||
link_lsi_common,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "redirect.h"
|
||||
|
||||
LsiRedirectProfile *lsi_redirect_profile_new(const char *name)
|
||||
{
|
||||
LsiRedirectProfile p = { .name = strdup(name), { 0 } };
|
||||
LsiRedirectProfile *ret = NULL;
|
||||
if (!p.name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = calloc(1, sizeof(LsiRedirectProfile));
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
*ret = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lsi_redirect_profile_free(LsiRedirectProfile *self)
|
||||
{
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free all chains */
|
||||
for (unsigned int i = 0; i < LSI_NUM_OPERATIONS; i++) {
|
||||
LsiRedirect *r = self->op_table[i];
|
||||
if (!r) {
|
||||
continue;
|
||||
}
|
||||
lsi_redirect_free(r);
|
||||
}
|
||||
|
||||
free(self->name);
|
||||
free(self);
|
||||
}
|
||||
|
||||
void lsi_redirect_profile_insert_rule(LsiRedirectProfile *self, LsiRedirect *redirect)
|
||||
{
|
||||
LsiRedirectOperation op;
|
||||
|
||||
switch (redirect->type) {
|
||||
case LSI_REDIRECT_PATH:
|
||||
op = LSI_OPERATION_OPEN;
|
||||
break;
|
||||
default:
|
||||
lsi_log_error("Attempted insert of unknown rule into '%s'", self->name);
|
||||
lsi_redirect_free(redirect);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set head or prepend the rule */
|
||||
if (self->op_table[op]) {
|
||||
redirect->next = self->op_table[op];
|
||||
self->op_table[op] = redirect;
|
||||
} else {
|
||||
self->op_table[op] = redirect;
|
||||
}
|
||||
}
|
||||
|
||||
LsiRedirect *lsi_redirect_new_path_replacement(const char *source_path, const char *target_path)
|
||||
{
|
||||
LsiRedirect *ret = NULL;
|
||||
|
||||
ret = calloc(1, sizeof(LsiRedirect));
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
ret->type = LSI_REDIRECT_PATH;
|
||||
ret->path_source = realpath(source_path, NULL);
|
||||
ret->path_target = realpath(target_path, NULL);
|
||||
|
||||
if (!ret->path_source || !ret->path_target) {
|
||||
lsi_redirect_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lsi_redirect_free(LsiRedirect *self)
|
||||
{
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pass it along */
|
||||
if (self->next) {
|
||||
lsi_redirect_free(self->next);
|
||||
}
|
||||
|
||||
switch (self->type) {
|
||||
case LSI_REDIRECT_PATH:
|
||||
default:
|
||||
free(self->path_source);
|
||||
free(self->path_target);
|
||||
break;
|
||||
}
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "redirect.h"
|
||||
|
||||
/**
|
||||
* Generator function is used to attempt creation of profiles based on the
|
||||
* steam directory
|
||||
*/
|
||||
typedef LsiRedirectProfile *(*lsi_profile_generator_func)(char *process_name, char *steam_root);
|
||||
|
||||
/**
|
||||
* Profile generator for Ark survival evolved
|
||||
*/
|
||||
LsiRedirectProfile *lsi_redirect_profile_new_ark(char *process_name, char *steam_root);
|
||||
|
||||
/**
|
||||
* Profile generator for Project Highrise
|
||||
*/
|
||||
LsiRedirectProfile *lsi_redirect_profile_new_project_highrise(char *process_name, char *steam_root);
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../common/log.h"
|
||||
#include "nica/util.h"
|
||||
#include "profile.h"
|
||||
#include "redirect.h"
|
||||
|
||||
#define ARK_BASE "steamapps/common/ARK/ShooterGame"
|
||||
#define ARK_CONTENT ARK_BASE "/Content"
|
||||
#define ARK_BINARY ARK_BASE "/Binaries/Linux/ShooterGame"
|
||||
|
||||
/**
|
||||
* This generator function is responsible for supporting ARK: Survival Evolved
|
||||
*
|
||||
* Simply it redirects the executable to open the correct asset when TheCenter
|
||||
* DLC is installed.
|
||||
*/
|
||||
LsiRedirectProfile *lsi_redirect_profile_new_ark(char *process_name, char *steam_path)
|
||||
{
|
||||
LsiRedirectProfile *p = NULL;
|
||||
LsiRedirect *redirect = NULL;
|
||||
autofree(char) *mic_source = NULL;
|
||||
autofree(char) *mic_target = NULL;
|
||||
autofree(char) *match_process = NULL;
|
||||
autofree(char) *test_process = NULL;
|
||||
|
||||
if (asprintf(&match_process, "%s/%s", steam_path, ARK_BINARY) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check it even exists */
|
||||
test_process = realpath(match_process, NULL);
|
||||
if (!test_process) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the process name now */
|
||||
if (strcmp(test_process, process_name) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *def_mic_source =
|
||||
ARK_CONTENT "/PrimalEarth/Environment/Water/Water_DepthBlur_MIC.uasset";
|
||||
static const char *def_mic_target =
|
||||
ARK_CONTENT "/Mods/TheCenter/Assets/Mic/Water_DepthBlur_MIC.uasset";
|
||||
|
||||
p = lsi_redirect_profile_new("ARK: Survival Evolved");
|
||||
if (!p) {
|
||||
fputs("OUT OF MEMORY\n", stderr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asprintf(&mic_source, "%s/%s", steam_path, def_mic_source) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
if (asprintf(&mic_target, "%s/%s", steam_path, def_mic_target) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Don't add a redirect if the paths don't exist. */
|
||||
redirect = lsi_redirect_new_path_replacement(mic_source, mic_target);
|
||||
if (!redirect) {
|
||||
goto unused;
|
||||
}
|
||||
|
||||
/* We're in, set our log ID now */
|
||||
lsi_log_set_id("ARK");
|
||||
|
||||
lsi_redirect_profile_insert_rule(p, redirect);
|
||||
|
||||
return p;
|
||||
|
||||
failed:
|
||||
/* Dead in the water.. */
|
||||
fputs("OUT OF MEMORY\n", stderr);
|
||||
unused:
|
||||
lsi_redirect_profile_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../common/files.h"
|
||||
#include "../common/log.h"
|
||||
#include "nica/util.h"
|
||||
#include "profile.h"
|
||||
#include "redirect.h"
|
||||
|
||||
#define PHR_PREF_DIR "unity3d/SomaSim/Project Highrise/prefs"
|
||||
#define PHR_PREF_FILE "unity3d/SomaSim/Project Highrise/prefs/prefs.txt"
|
||||
|
||||
#if UINTPTR_MAX == 0xffffffffffffffff
|
||||
#define PHR_BINARY "steamapps/common/Project Highrise/Game.x86_64"
|
||||
#else
|
||||
#define PHR_BINARY "steamapps/common/Project Highrise/Game.x86"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This generator function is responsible for supporting: Project Highrise
|
||||
*
|
||||
* Currently a bug exists in Projec Highrise, where on the second launch, i.e.
|
||||
* preferences tree exists, it will try to load/map the preferences directory
|
||||
* as a file, and fails to use the correct *file path*
|
||||
*
|
||||
* This is a temporary workaround and we'll let them know what we found.
|
||||
*/
|
||||
LsiRedirectProfile *lsi_redirect_profile_new_project_highrise(char *process_name, char *steam_path)
|
||||
{
|
||||
LsiRedirectProfile *p = NULL;
|
||||
LsiRedirect *redirect = NULL;
|
||||
autofree(char) *p_source = NULL;
|
||||
autofree(char) *p_target = NULL;
|
||||
autofree(char) *match_process = NULL;
|
||||
autofree(char) *test_process = NULL;
|
||||
autofree(char) *config_dir = NULL;
|
||||
|
||||
if (asprintf(&match_process, "%s/%s", steam_path, PHR_BINARY) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check it even exists */
|
||||
test_process = realpath(match_process, NULL);
|
||||
if (!test_process) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the process name now */
|
||||
if (strcmp(test_process, process_name) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config_dir = lsi_get_user_config_dir();
|
||||
if (!config_dir) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = lsi_redirect_profile_new("Project Highrise");
|
||||
if (!p) {
|
||||
fputs("OUT OF MEMORY\n", stderr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asprintf(&p_source, "%s/%s", config_dir, PHR_PREF_DIR) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
if (asprintf(&p_target, "%s/%s", config_dir, PHR_PREF_FILE) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Don't add a redirect if the paths don't exist. */
|
||||
redirect = lsi_redirect_new_path_replacement(p_source, p_target);
|
||||
if (!redirect) {
|
||||
goto unused;
|
||||
}
|
||||
|
||||
/* We're in, set our log ID now */
|
||||
lsi_log_set_id("ProjectHighrise");
|
||||
|
||||
lsi_redirect_profile_insert_rule(p, redirect);
|
||||
|
||||
return p;
|
||||
|
||||
failed:
|
||||
/* Dead in the water.. */
|
||||
fputs("OUT OF MEMORY\n", stderr);
|
||||
unused:
|
||||
lsi_redirect_profile_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* The type of redirect required
|
||||
*/
|
||||
typedef enum {
|
||||
LSI_REDIRECT_MIN = 1,
|
||||
LSI_REDIRECT_PATH,
|
||||
} LsiRedirectType;
|
||||
|
||||
/**
|
||||
* LsiRedirect describes the configuration required for each operation.
|
||||
*/
|
||||
typedef struct LsiRedirect {
|
||||
LsiRedirectType type;
|
||||
union {
|
||||
/* Path replacement */
|
||||
struct {
|
||||
char *path_source;
|
||||
char *path_target;
|
||||
};
|
||||
};
|
||||
struct LsiRedirect *next;
|
||||
} LsiRedirect;
|
||||
|
||||
/**
|
||||
* LsiRedirectOperation specifies the syscall we're intended for.
|
||||
*/
|
||||
typedef enum { LSI_OPERATION_OPEN = 0, LSI_NUM_OPERATIONS } LsiRedirectOperation;
|
||||
|
||||
/**
|
||||
* We build an LsiRedirectProfile to match the current process.
|
||||
* It contains a table of LsiRedirect members corresponding to a given
|
||||
* op, i.e:
|
||||
*
|
||||
* op_table[LSI_OPERATION_OPEN]
|
||||
*/
|
||||
typedef struct LsiRedirectProfile {
|
||||
char *name; /**< Name for this profile */
|
||||
|
||||
LsiRedirect *op_table[LSI_NUM_OPERATIONS]; /* vtable information */
|
||||
} LsiRedirectProfile;
|
||||
|
||||
/**
|
||||
* Construct a new LsiRedirectProfile
|
||||
*
|
||||
* @param name Profile name
|
||||
* @returns A newly allocated LsiRedirectProfile
|
||||
*/
|
||||
LsiRedirectProfile *lsi_redirect_profile_new(const char *name);
|
||||
|
||||
/**
|
||||
* Free a previously allocated LsiRedirectProfile
|
||||
*
|
||||
* @param profile Pointer to an allocated LsiRedirectProfile
|
||||
*/
|
||||
void lsi_redirect_profile_free(LsiRedirectProfile *profile);
|
||||
|
||||
/**
|
||||
* Attempt insert of a redirect rule into this profile
|
||||
*
|
||||
* @param profile Pointer to a valid LsiRedirectProfile
|
||||
* @param redirect Pointer to an allocated LsiRedirect
|
||||
*/
|
||||
void lsi_redirect_profile_insert_rule(LsiRedirectProfile *self, LsiRedirect *redirect);
|
||||
|
||||
/* LsiRedirect APIs follow */
|
||||
|
||||
/**
|
||||
* Construct a new LsiRedirect to perform path replacements
|
||||
*/
|
||||
LsiRedirect *lsi_redirect_new_path_replacement(const char *source_path, const char *target_path);
|
||||
|
||||
/**
|
||||
* Attempt to free this redirect
|
||||
*
|
||||
* @param redirect Pointer to allocated LsiRedirect
|
||||
*/
|
||||
void lsi_redirect_free(LsiRedirect *self);
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=8 tabstop=8 expandtab:
|
||||
* :indentSize=8:tabSize=8:noTabs=true:
|
||||
*/
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
global:
|
||||
fopen64;
|
||||
open;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
if shim_behaviour == 'replacement'
|
||||
shim_target_name = 'steam'
|
||||
else
|
||||
shim_target_name = 'lsi-steam'
|
||||
endif
|
||||
|
||||
if shim_behaviour != 'none'
|
||||
shim_sources = [
|
||||
'shim.c',
|
||||
]
|
||||
|
||||
shim = executable(
|
||||
shim_target_name,
|
||||
sources: shim_sources + nica_sources,
|
||||
include_directories: nica_includes,
|
||||
dependencies: [
|
||||
link_lsi,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
endif
|
||||
+68
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of linux-steam-integration.
|
||||
*
|
||||
* Copyright © 2016 Ikey Doherty
|
||||
* Copyright © 2016-2017 Ikey Doherty <ikey@solus-project.com>
|
||||
*
|
||||
* linux-steam-integration is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
@@ -12,11 +12,13 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/files.h"
|
||||
#include "config.h"
|
||||
#include "lsi.h"
|
||||
|
||||
@@ -26,16 +28,56 @@
|
||||
*/
|
||||
#define EMUL32BIN "linux32"
|
||||
|
||||
/**
|
||||
* Audit path is used for the libintercept library to ensure Steam only uses the
|
||||
* host SDL, etc.
|
||||
*/
|
||||
#define AUDIT_PATH "/usr/\$LIB/liblsi-intercept.so"
|
||||
|
||||
/**
|
||||
* Redirect path is used for the libredirect library to perform internal
|
||||
* redirections in functions like `open()` where needed to hotfix games
|
||||
* at runtime.
|
||||
*/
|
||||
#define REDIRECT_PATH "/usr/\$LIB/liblsi-redirect.so"
|
||||
|
||||
/**
|
||||
* Set up LD_PRELOAD, respecting an existing LD_PRELOAD and forcing ourselves
|
||||
* to be first in the list.
|
||||
*/
|
||||
static void shim_set_ld_preload(void)
|
||||
{
|
||||
const char *preload = NULL;
|
||||
static char tgt[PATH_MAX] = { 0 };
|
||||
|
||||
preload = getenv("LD_PRELOAD");
|
||||
if (!preload) {
|
||||
setenv("LD_PRELOAD", REDIRECT_PATH, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (snprintf(tgt, sizeof(tgt), "%s:%s", REDIRECT_PATH, preload) < 0) {
|
||||
setenv("LD_PRELOAD", REDIRECT_PATH, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
setenv("LD_PRELOAD", tgt, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
LsiConfig config = { 0 };
|
||||
bool is_x86_64;
|
||||
const char *n_argv[argc + 2];
|
||||
const char *exec_command = NULL;
|
||||
/* Use the appropriate Steam depending on configuration */
|
||||
const char *lsi_exec_bin = NULL;
|
||||
int i = 1;
|
||||
int8_t off = 0;
|
||||
int (*vfunc)(const char *, char *const argv[]) = NULL;
|
||||
|
||||
lsi_exec_bin = STEAM_BINARY;
|
||||
|
||||
/* Initialise config */
|
||||
if (!lsi_config_load(&config)) {
|
||||
lsi_config_load_defaults(&config);
|
||||
@@ -43,8 +85,8 @@ int main(int argc, char **argv)
|
||||
|
||||
is_x86_64 = lsi_system_is_64bit();
|
||||
|
||||
if (!lsi_file_exists(STEAM_BINARY)) {
|
||||
lsi_report_failure("Steam isn't currently installed at %s", STEAM_BINARY);
|
||||
if (!lsi_file_exists(lsi_exec_bin)) {
|
||||
lsi_report_failure("Steam isn't currently installed at %s", lsi_exec_bin);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -52,6 +94,18 @@ int main(int argc, char **argv)
|
||||
if (config.use_native_runtime) {
|
||||
/* Explicitly disable the runtime */
|
||||
setenv("STEAM_RUNTIME", "0", 1);
|
||||
#ifdef HAVE_LIBINTERCEPT
|
||||
/* Only use libintercept in combination with native runtime! */
|
||||
if (config.use_libintercept) {
|
||||
setenv("LD_AUDIT", AUDIT_PATH, 1);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBREDIRECT
|
||||
/* Only use libredirect in combination with native runtime! */
|
||||
if (config.use_libredirect) {
|
||||
shim_set_ld_preload();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* Only preload when needed. */
|
||||
if (lsi_system_requires_preload()) {
|
||||
@@ -64,20 +118,27 @@ int main(int argc, char **argv)
|
||||
* usage of dbus by Steam. Help them out */
|
||||
setenv("DBUS_FATAL_WARNINGS", "0", 1);
|
||||
|
||||
/* A recent regression is to interpret XMODIFIERS and then fail to
|
||||
* make it beyond `SDL_InitSubSystem` due to `InitIME` failing to
|
||||
* properly use D-BUS ...
|
||||
*/
|
||||
unsetenv("XMODIFIERS");
|
||||
unsetenv("GTK_MODULES");
|
||||
|
||||
memset(&n_argv, 0, sizeof(char *) * (argc + 2));
|
||||
|
||||
/* If we're 64-bit and 32-bit is forced, proxy via linux32 */
|
||||
if (config.force_32 && is_x86_64) {
|
||||
exec_command = EMUL32BIN;
|
||||
n_argv[0] = EMUL32BIN;
|
||||
n_argv[1] = STEAM_BINARY;
|
||||
n_argv[1] = lsi_exec_bin;
|
||||
off = 1;
|
||||
/* Use linux32 in the path */
|
||||
vfunc = execvp;
|
||||
} else {
|
||||
/* Directly call STEAM_BINARY */
|
||||
exec_command = STEAM_BINARY;
|
||||
n_argv[0] = STEAM_BINARY;
|
||||
/* Directly call lsi_exec_bin */
|
||||
exec_command = lsi_exec_bin;
|
||||
n_argv[0] = lsi_exec_bin;
|
||||
/* Full path here due to shadow nature */
|
||||
vfunc = execv;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
env -i DBUS_SESSION_ADDRESS=$DBUS_SESSION_ADDRESS \
|
||||
PATH=$PATH \
|
||||
DISPLAY=$DISPLAY \
|
||||
HOME=$HOME \
|
||||
USER=$USER \
|
||||
USERNAME=$USERNAME \
|
||||
LD_AUDIT="`pwd`/buildroot/install/usr/\$LIB/liblsi-intercept.so" \
|
||||
LD_PRELOAD="/usr/\$LIB/libxcb.so.1:/usr/\$LIB/libX11.so.6:/usr/\$LIB/libstdc++.so.6" \
|
||||
DBUS_FATAL_WARNINGS=0 \
|
||||
STEAM_RUNTIME=0 /usr/lib64/steam/steam
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
clang-format -i $(find . -name '*.[ch]')
|
||||
clang-format -i $(find . -not -path '*/libnica/*' -name '*.[ch]')
|
||||
|
||||
Reference in New Issue
Block a user