SDL  2.0
SDL_syspower.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #ifndef SDL_POWER_DISABLED
24 #if SDL_POWER_LINUX
25 
26 #include <stdio.h>
27 #include <unistd.h>
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <dirent.h>
32 #include <fcntl.h>
33 
34 #include "SDL_power.h"
35 #include "../SDL_syspower.h"
36 
37 #include "../../core/linux/SDL_dbus.h"
38 
39 static const char *proc_apm_path = "/proc/apm";
40 static const char *proc_acpi_battery_path = "/proc/acpi/battery";
41 static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter";
42 static const char *sys_class_power_supply_path = "/sys/class/power_supply";
43 
44 static int
45 open_power_file(const char *base, const char *node, const char *key)
46 {
47  const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3;
48  char *path = (char *) alloca(pathlen);
49  if (path == NULL) {
50  return -1; /* oh well. */
51  }
52 
53  snprintf(path, pathlen, "%s/%s/%s", base, node, key);
54  return open(path, O_RDONLY);
55 }
56 
57 
58 static SDL_bool
59 read_power_file(const char *base, const char *node, const char *key,
60  char *buf, size_t buflen)
61 {
62  ssize_t br = 0;
63  const int fd = open_power_file(base, node, key);
64  if (fd == -1) {
65  return SDL_FALSE;
66  }
67  br = read(fd, buf, buflen-1);
68  close(fd);
69  if (br < 0) {
70  return SDL_FALSE;
71  }
72  buf[br] = '\0'; /* null-terminate the string. */
73  return SDL_TRUE;
74 }
75 
76 
77 static SDL_bool
78 make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
79 {
80  char *ptr = *_ptr;
81 
82  while (*ptr == ' ') {
83  ptr++; /* skip whitespace. */
84  }
85 
86  if (*ptr == '\0') {
87  return SDL_FALSE; /* EOF. */
88  }
89 
90  *_key = ptr;
91 
92  while ((*ptr != ':') && (*ptr != '\0')) {
93  ptr++;
94  }
95 
96  if (*ptr == '\0') {
97  return SDL_FALSE; /* (unexpected) EOF. */
98  }
99 
100  *(ptr++) = '\0'; /* terminate the key. */
101 
102  while ((*ptr == ' ') && (*ptr != '\0')) {
103  ptr++; /* skip whitespace. */
104  }
105 
106  if (*ptr == '\0') {
107  return SDL_FALSE; /* (unexpected) EOF. */
108  }
109 
110  *_val = ptr;
111 
112  while ((*ptr != '\n') && (*ptr != '\0')) {
113  ptr++;
114  }
115 
116  if (*ptr != '\0') {
117  *(ptr++) = '\0'; /* terminate the value. */
118  }
119 
120  *_ptr = ptr; /* store for next time. */
121  return SDL_TRUE;
122 }
123 
124 static void
125 check_proc_acpi_battery(const char * node, SDL_bool * have_battery,
126  SDL_bool * charging, int *seconds, int *percent)
127 {
128  const char *base = proc_acpi_battery_path;
129  char info[1024];
130  char state[1024];
131  char *ptr = NULL;
132  char *key = NULL;
133  char *val = NULL;
134  SDL_bool charge = SDL_FALSE;
135  SDL_bool choose = SDL_FALSE;
136  int maximum = -1;
137  int remaining = -1;
138  int secs = -1;
139  int pct = -1;
140 
141  if (!read_power_file(base, node, "state", state, sizeof (state))) {
142  return;
143  } else if (!read_power_file(base, node, "info", info, sizeof (info))) {
144  return;
145  }
146 
147  ptr = &state[0];
148  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
149  if (strcmp(key, "present") == 0) {
150  if (strcmp(val, "yes") == 0) {
151  *have_battery = SDL_TRUE;
152  }
153  } else if (strcmp(key, "charging state") == 0) {
154  /* !!! FIXME: what exactly _does_ charging/discharging mean? */
155  if (strcmp(val, "charging/discharging") == 0) {
156  charge = SDL_TRUE;
157  } else if (strcmp(val, "charging") == 0) {
158  charge = SDL_TRUE;
159  }
160  } else if (strcmp(key, "remaining capacity") == 0) {
161  char *endptr = NULL;
162  const int cvt = (int) strtol(val, &endptr, 10);
163  if (*endptr == ' ') {
164  remaining = cvt;
165  }
166  }
167  }
168 
169  ptr = &info[0];
170  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
171  if (strcmp(key, "design capacity") == 0) {
172  char *endptr = NULL;
173  const int cvt = (int) strtol(val, &endptr, 10);
174  if (*endptr == ' ') {
175  maximum = cvt;
176  }
177  }
178  }
179 
180  if ((maximum >= 0) && (remaining >= 0)) {
181  pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
182  if (pct < 0) {
183  pct = 0;
184  } else if (pct > 100) {
185  pct = 100;
186  }
187  }
188 
189  /* !!! FIXME: calculate (secs). */
190 
191  /*
192  * We pick the battery that claims to have the most minutes left.
193  * (failing a report of minutes, we'll take the highest percent.)
194  */
195  if ((secs < 0) && (*seconds < 0)) {
196  if ((pct < 0) && (*percent < 0)) {
197  choose = SDL_TRUE; /* at least we know there's a battery. */
198  }
199  if (pct > *percent) {
200  choose = SDL_TRUE;
201  }
202  } else if (secs > *seconds) {
203  choose = SDL_TRUE;
204  }
205 
206  if (choose) {
207  *seconds = secs;
208  *percent = pct;
209  *charging = charge;
210  }
211 }
212 
213 static void
214 check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac)
215 {
216  const char *base = proc_acpi_ac_adapter_path;
217  char state[256];
218  char *ptr = NULL;
219  char *key = NULL;
220  char *val = NULL;
221 
222  if (!read_power_file(base, node, "state", state, sizeof (state))) {
223  return;
224  }
225 
226  ptr = &state[0];
227  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
228  if (strcmp(key, "state") == 0) {
229  if (strcmp(val, "on-line") == 0) {
230  *have_ac = SDL_TRUE;
231  }
232  }
233  }
234 }
235 
236 
237 SDL_bool
239  int *seconds, int *percent)
240 {
241  struct dirent *dent = NULL;
242  DIR *dirp = NULL;
243  SDL_bool have_battery = SDL_FALSE;
244  SDL_bool have_ac = SDL_FALSE;
245  SDL_bool charging = SDL_FALSE;
246 
247  *seconds = -1;
248  *percent = -1;
249  *state = SDL_POWERSTATE_UNKNOWN;
250 
251  dirp = opendir(proc_acpi_battery_path);
252  if (dirp == NULL) {
253  return SDL_FALSE; /* can't use this interface. */
254  } else {
255  while ((dent = readdir(dirp)) != NULL) {
256  const char *node = dent->d_name;
257  check_proc_acpi_battery(node, &have_battery, &charging,
258  seconds, percent);
259  }
260  closedir(dirp);
261  }
262 
263  dirp = opendir(proc_acpi_ac_adapter_path);
264  if (dirp == NULL) {
265  return SDL_FALSE; /* can't use this interface. */
266  } else {
267  while ((dent = readdir(dirp)) != NULL) {
268  const char *node = dent->d_name;
269  check_proc_acpi_ac_adapter(node, &have_ac);
270  }
271  closedir(dirp);
272  }
273 
274  if (!have_battery) {
275  *state = SDL_POWERSTATE_NO_BATTERY;
276  } else if (charging) {
277  *state = SDL_POWERSTATE_CHARGING;
278  } else if (have_ac) {
279  *state = SDL_POWERSTATE_CHARGED;
280  } else {
281  *state = SDL_POWERSTATE_ON_BATTERY;
282  }
283 
284  return SDL_TRUE; /* definitive answer. */
285 }
286 
287 
288 static SDL_bool
289 next_string(char **_ptr, char **_str)
290 {
291  char *ptr = *_ptr;
292  char *str = *_str;
293 
294  while (*ptr == ' ') { /* skip any spaces... */
295  ptr++;
296  }
297 
298  if (*ptr == '\0') {
299  return SDL_FALSE;
300  }
301 
302  str = ptr;
303  while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
304  ptr++;
305 
306  if (*ptr != '\0')
307  *(ptr++) = '\0';
308 
309  *_str = str;
310  *_ptr = ptr;
311  return SDL_TRUE;
312 }
313 
314 static SDL_bool
315 int_string(char *str, int *val)
316 {
317  char *endptr = NULL;
318  *val = (int) strtol(str, &endptr, 0);
319  return ((*str != '\0') && (*endptr == '\0'));
320 }
321 
322 /* http://lxr.linux.no/linux+v2.6.29/drivers/char/apm-emulation.c */
323 SDL_bool
325  int *seconds, int *percent)
326 {
327  SDL_bool need_details = SDL_FALSE;
328  int ac_status = 0;
329  int battery_status = 0;
330  int battery_flag = 0;
331  int battery_percent = 0;
332  int battery_time = 0;
333  const int fd = open(proc_apm_path, O_RDONLY);
334  char buf[128];
335  char *ptr = &buf[0];
336  char *str = NULL;
337  ssize_t br;
338 
339  if (fd == -1) {
340  return SDL_FALSE; /* can't use this interface. */
341  }
342 
343  br = read(fd, buf, sizeof (buf) - 1);
344  close(fd);
345 
346  if (br < 0) {
347  return SDL_FALSE;
348  }
349 
350  buf[br] = '\0'; /* null-terminate the string. */
351  if (!next_string(&ptr, &str)) { /* driver version */
352  return SDL_FALSE;
353  }
354  if (!next_string(&ptr, &str)) { /* BIOS version */
355  return SDL_FALSE;
356  }
357  if (!next_string(&ptr, &str)) { /* APM flags */
358  return SDL_FALSE;
359  }
360 
361  if (!next_string(&ptr, &str)) { /* AC line status */
362  return SDL_FALSE;
363  } else if (!int_string(str, &ac_status)) {
364  return SDL_FALSE;
365  }
366 
367  if (!next_string(&ptr, &str)) { /* battery status */
368  return SDL_FALSE;
369  } else if (!int_string(str, &battery_status)) {
370  return SDL_FALSE;
371  }
372  if (!next_string(&ptr, &str)) { /* battery flag */
373  return SDL_FALSE;
374  } else if (!int_string(str, &battery_flag)) {
375  return SDL_FALSE;
376  }
377  if (!next_string(&ptr, &str)) { /* remaining battery life percent */
378  return SDL_FALSE;
379  }
380  if (str[strlen(str) - 1] == '%') {
381  str[strlen(str) - 1] = '\0';
382  }
383  if (!int_string(str, &battery_percent)) {
384  return SDL_FALSE;
385  }
386 
387  if (!next_string(&ptr, &str)) { /* remaining battery life time */
388  return SDL_FALSE;
389  } else if (!int_string(str, &battery_time)) {
390  return SDL_FALSE;
391  }
392 
393  if (!next_string(&ptr, &str)) { /* remaining battery life time units */
394  return SDL_FALSE;
395  } else if (strcmp(str, "min") == 0) {
396  battery_time *= 60;
397  }
398 
399  if (battery_flag == 0xFF) { /* unknown state */
400  *state = SDL_POWERSTATE_UNKNOWN;
401  } else if (battery_flag & (1 << 7)) { /* no battery */
402  *state = SDL_POWERSTATE_NO_BATTERY;
403  } else if (battery_flag & (1 << 3)) { /* charging */
404  *state = SDL_POWERSTATE_CHARGING;
405  need_details = SDL_TRUE;
406  } else if (ac_status == 1) {
407  *state = SDL_POWERSTATE_CHARGED; /* on AC, not charging. */
408  need_details = SDL_TRUE;
409  } else {
410  *state = SDL_POWERSTATE_ON_BATTERY;
411  need_details = SDL_TRUE;
412  }
413 
414  *percent = -1;
415  *seconds = -1;
416  if (need_details) {
417  const int pct = battery_percent;
418  const int secs = battery_time;
419 
420  if (pct >= 0) { /* -1 == unknown */
421  *percent = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
422  }
423  if (secs >= 0) { /* -1 == unknown */
424  *seconds = secs;
425  }
426  }
427 
428  return SDL_TRUE;
429 }
430 
431 SDL_bool
432 SDL_GetPowerInfo_Linux_sys_class_power_supply(SDL_PowerState *state, int *seconds, int *percent)
433 {
434  const char *base = sys_class_power_supply_path;
435  struct dirent *dent;
436  DIR *dirp;
437 
438  dirp = opendir(base);
439  if (!dirp) {
440  return SDL_FALSE;
441  }
442 
443  *state = SDL_POWERSTATE_NO_BATTERY; /* assume we're just plugged in. */
444  *seconds = -1;
445  *percent = -1;
446 
447  while ((dent = readdir(dirp)) != NULL) {
448  const char *name = dent->d_name;
449  SDL_bool choose = SDL_FALSE;
450  char str[64];
451  SDL_PowerState st;
452  int secs;
453  int pct;
454 
455  if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
456  continue; /* skip these, of course. */
457  } else if (!read_power_file(base, name, "type", str, sizeof (str))) {
458  continue; /* Don't know _what_ we're looking at. Give up on it. */
459  } else if (SDL_strcmp(str, "Battery\n") != 0) {
460  continue; /* we don't care about UPS and such. */
461  }
462 
463  /* if the scope is "device," it might be something like a PS4
464  controller reporting its own battery, and not something that powers
465  the system. Most system batteries don't list a scope at all; we
466  assume it's a system battery if not specified. */
467  if (read_power_file(base, name, "scope", str, sizeof (str))) {
468  if (SDL_strcmp(str, "device\n") == 0) {
469  continue; /* skip external devices with their own batteries. */
470  }
471  }
472 
473  /* some drivers don't offer this, so if it's not explicitly reported assume it's present. */
474  if (read_power_file(base, name, "present", str, sizeof (str)) && (SDL_strcmp(str, "0\n") == 0)) {
476  } else if (!read_power_file(base, name, "status", str, sizeof (str))) {
477  st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
478  } else if (SDL_strcmp(str, "Charging\n") == 0) {
480  } else if (SDL_strcmp(str, "Discharging\n") == 0) {
482  } else if ((SDL_strcmp(str, "Full\n") == 0) || (SDL_strcmp(str, "Not charging\n") == 0)) {
484  } else {
485  st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
486  }
487 
488  if (!read_power_file(base, name, "capacity", str, sizeof (str))) {
489  pct = -1;
490  } else {
491  pct = SDL_atoi(str);
492  pct = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
493  }
494 
495  if (!read_power_file(base, name, "time_to_empty_now", str, sizeof (str))) {
496  secs = -1;
497  } else {
498  secs = SDL_atoi(str);
499  secs = (secs <= 0) ? -1 : secs; /* 0 == unknown */
500  }
501 
502  /*
503  * We pick the battery that claims to have the most minutes left.
504  * (failing a report of minutes, we'll take the highest percent.)
505  */
506  if ((secs < 0) && (*seconds < 0)) {
507  if ((pct < 0) && (*percent < 0)) {
508  choose = SDL_TRUE; /* at least we know there's a battery. */
509  } else if (pct > *percent) {
510  choose = SDL_TRUE;
511  }
512  } else if (secs > *seconds) {
513  choose = SDL_TRUE;
514  }
515 
516  if (choose) {
517  *seconds = secs;
518  *percent = pct;
519  *state = st;
520  }
521  }
522 
523  closedir(dirp);
524  return SDL_TRUE; /* don't look any further. */
525 }
526 
527 
528 /* d-bus queries to org.freedesktop.UPower. */
529 #if SDL_USE_LIBDBUS
530 #define UPOWER_DBUS_NODE "org.freedesktop.UPower"
531 #define UPOWER_DBUS_PATH "/org/freedesktop/UPower"
532 #define UPOWER_DBUS_INTERFACE "org.freedesktop.UPower"
533 #define UPOWER_DEVICE_DBUS_INTERFACE "org.freedesktop.UPower.Device"
534 
535 static void
536 check_upower_device(DBusConnection *conn, const char *path, SDL_PowerState *state, int *seconds, int *percent)
537 {
538  SDL_bool choose = SDL_FALSE;
539  SDL_PowerState st;
540  int secs;
541  int pct;
542  Uint32 ui32 = 0;
543  Sint64 si64 = 0;
544  double d = 0.0;
545 
546  if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "Type", DBUS_TYPE_UINT32, &ui32)) {
547  return; /* Don't know _what_ we're looking at. Give up on it. */
548  } else if (ui32 != 2) { /* 2==Battery*/
549  return; /* we don't care about UPS and such. */
550  } else if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "PowerSupply", DBUS_TYPE_BOOLEAN, &ui32)) {
551  return;
552  } else if (!ui32) {
553  return; /* we don't care about random devices with batteries, like wireless controllers, etc */
554  } else if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "IsPresent", DBUS_TYPE_BOOLEAN, &ui32)) {
555  return;
556  } else if (!ui32) {
558  } else if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "State", DBUS_TYPE_UINT32, &ui32)) {
559  st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
560  } else if (ui32 == 1) { /* 1 == charging */
562  } else if ((ui32 == 2) || (ui32 == 3)) { /* 2 == discharging, 3 == empty. */
564  } else if (ui32 == 4) { /* 4 == full */
566  } else {
567  st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
568  }
569 
570  if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "Percentage", DBUS_TYPE_DOUBLE, &d)) {
571  pct = -1; /* some old/cheap batteries don't set this property. */
572  } else {
573  pct = (int) d;
574  pct = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
575  }
576 
577  if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "TimeToEmpty", DBUS_TYPE_INT64, &si64)) {
578  secs = -1;
579  } else {
580  secs = (int) si64;
581  secs = (secs <= 0) ? -1 : secs; /* 0 == unknown */
582  }
583 
584  /*
585  * We pick the battery that claims to have the most minutes left.
586  * (failing a report of minutes, we'll take the highest percent.)
587  */
588  if ((secs < 0) && (*seconds < 0)) {
589  if ((pct < 0) && (*percent < 0)) {
590  choose = SDL_TRUE; /* at least we know there's a battery. */
591  } else if (pct > *percent) {
592  choose = SDL_TRUE;
593  }
594  } else if (secs > *seconds) {
595  choose = SDL_TRUE;
596  }
597 
598  if (choose) {
599  *seconds = secs;
600  *percent = pct;
601  *state = st;
602  }
603 }
604 #endif
605 
606 SDL_bool
607 SDL_GetPowerInfo_Linux_org_freedesktop_upower(SDL_PowerState *state, int *seconds, int *percent)
608 {
610 
611  #if SDL_USE_LIBDBUS
612  SDL_DBusContext *dbus = SDL_DBus_GetContext();
613  char **paths = NULL;
614  int i, numpaths = 0;
615 
616  if (!SDL_DBus_CallMethodOnConnection(dbus->system_conn, UPOWER_DBUS_NODE, UPOWER_DBUS_PATH, UPOWER_DBUS_INTERFACE, "EnumerateDevices",
617  DBUS_TYPE_INVALID,
618  DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &numpaths, DBUS_TYPE_INVALID)) {
619  return SDL_FALSE; /* try a different approach than UPower. */
620  }
621 
622  retval = SDL_TRUE; /* Clearly we can use this interface. */
623  *state = SDL_POWERSTATE_NO_BATTERY; /* assume we're just plugged in. */
624  *seconds = -1;
625  *percent = -1;
626 
627  for (i = 0; i < numpaths; i++) {
628  check_upower_device(dbus->system_conn, paths[i], state, seconds, percent);
629  }
630 
631  if (dbus) {
632  dbus->free_string_array(paths);
633  }
634  #endif /* SDL_USE_LIBDBUS */
635 
636  return retval;
637 }
638 
639 #endif /* SDL_POWER_LINUX */
640 #endif /* SDL_POWER_DISABLED */
641 
642 /* vi: set ts=4 sw=4 expandtab: */
SDL_bool SDL_GetPowerInfo_Linux_sys_class_power_supply(SDL_PowerState *, int *, int *)
struct xkb_state * state
SDL_bool SDL_GetPowerInfo_Linux_org_freedesktop_upower(SDL_PowerState *, int *, int *)
uint32_t Uint32
Definition: SDL_stdinc.h:181
GLuint const GLchar * name
SDL_bool retval
GLuint GLfloat * val
GLuint64 key
Definition: gl2ext.h:2192
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
GLenum GLuint GLenum GLsizei const GLchar * buf
#define SDL_atoi
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
SDL_PowerState
The basic state for the system&#39;s power supply.
Definition: SDL_power.h:42
SDL_bool SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState *, int *, int *)
GLsizei const GLchar *const * path
#define SDL_strcmp
int64_t Sint64
Definition: SDL_stdinc.h:188
GLsizei const GLuint * paths
SDL_bool SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState *, int *, int *)
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508