1/*
2   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3   All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables.  You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL".  If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so.  If you do not wish to do
30so, delete this exception statement from your version.
31*/
32
33/* -- pm.c -- */
34#include "x11vnc.h"
35#include "cleanup.h"
36
37void check_pm(void);
38void set_dpms_mode(char *mode);
39static void check_fbpm(void);
40static void check_dpms(void);
41
42#if LIBVNCSERVER_HAVE_FBPM
43#include <X11/Xmd.h>
44#include <X11/extensions/fbpm.h>
45#endif
46
47#if LIBVNCSERVER_HAVE_DPMS
48#include <X11/extensions/dpms.h>
49#endif
50
51void check_pm(void) {
52	static int skip = -1;
53	if (skip < 0) {
54		skip = 0;
55		if (getenv("X11VNC_NO_CHECK_PM")) {
56			skip = 1;
57		}
58	}
59	if (skip) {
60		return;
61	}
62	check_fbpm();
63	check_dpms();
64	/* someday dpms activities? */
65}
66
67static void check_fbpm(void) {
68	static int init_fbpm = 0;
69#if LIBVNCSERVER_HAVE_FBPM
70	static int fbpm_capable = 0;
71	static time_t last_fbpm = 0;
72	int db = 0;
73
74	CARD16 level;
75	BOOL enabled;
76
77	RAWFB_RET_VOID
78
79	if (! init_fbpm) {
80		if (getenv("FBPM_DEBUG")) {
81			db = atoi(getenv("FBPM_DEBUG"));
82		}
83		if (FBPMCapable(dpy)) {
84			fbpm_capable = 1;
85			rfbLog("X display is capable of FBPM.\n");
86			if (watch_fbpm) {
87				rfbLog("Preventing low-power FBPM modes when"
88				    " clients are connected.\n");
89			}
90		} else {
91			if (! raw_fb_str) {
92				rfbLog("X display is not capable of FBPM.\n");
93			}
94			fbpm_capable = 0;
95		}
96		init_fbpm = 1;
97	}
98
99	if (! watch_fbpm) {
100		return;
101	}
102	if (! fbpm_capable) {
103		return;
104	}
105	if (! client_count) {
106		return;
107	}
108	if (time(NULL) < last_fbpm + 5) {
109		return;
110	}
111	last_fbpm = time(NULL);
112
113	if (FBPMInfo(dpy, &level, &enabled)) {
114		if (db) fprintf(stderr, "FBPMInfo level: %d enabled: %d\n", level, enabled);
115
116		if (enabled && level != FBPMModeOn) {
117			char *from = "unknown-fbpm-state";
118			XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
119			trapped_xerror = 0;
120
121			if (level == FBPMModeStandby) {
122				from = "FBPMModeStandby";
123			} else if (level == FBPMModeSuspend) {
124				from = "FBPMModeSuspend";
125			} else if (level == FBPMModeOff) {
126				from = "FBPMModeOff";
127			}
128
129			rfbLog("switching FBPM state from %s to FBPMModeOn\n", from);
130
131			FBPMForceLevel(dpy, FBPMModeOn);
132
133			XSetErrorHandler(old_handler);
134			trapped_xerror = 0;
135		}
136	} else {
137		if (db) fprintf(stderr, "FBPMInfo failed.\n");
138	}
139#else
140	RAWFB_RET_VOID
141	if (! init_fbpm) {
142		if (! raw_fb_str) {
143			rfbLog("X FBPM extension not supported.\n");
144		}
145		init_fbpm = 1;
146	}
147#endif
148}
149
150void set_dpms_mode(char *mode) {
151#if NO_X11
152	return;
153#else
154	RAWFB_RET_VOID
155#if LIBVNCSERVER_HAVE_DPMS
156	if (dpy && DPMSCapable(dpy)) {
157		CARD16 level;
158		CARD16 want;
159		BOOL enabled;
160		if (!strcmp(mode, "off")) {
161			want = DPMSModeOff;
162		} else if (!strcmp(mode, "on")) {
163			want = DPMSModeOn;
164		} else if (!strcmp(mode, "standby")) {
165			want = DPMSModeStandby;
166		} else if (!strcmp(mode, "suspend")) {
167			want = DPMSModeSuspend;
168		} else if (!strcmp(mode, "enable")) {
169			DPMSEnable(dpy);
170			return;
171		} else if (!strcmp(mode, "disable")) {
172			DPMSDisable(dpy);
173			return;
174		} else {
175			return;
176		}
177		if (DPMSInfo(dpy, &level, &enabled)) {
178			char *from = "unk";
179			if (enabled && level != want) {
180				XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
181				trapped_xerror = 0;
182
183				rfbLog("DPMSInfo level: %d enabled: %d\n", level, enabled);
184				if (level == DPMSModeStandby) {
185					from = "DPMSModeStandby";
186				} else if (level == DPMSModeSuspend) {
187					from = "DPMSModeSuspend";
188				} else if (level == DPMSModeOff) {
189					from = "DPMSModeOff";
190				} else if (level == DPMSModeOn) {
191					from = "DPMSModeOn";
192				}
193
194				rfbLog("switching DPMS state from %s to %s\n", from, mode);
195
196				DPMSForceLevel(dpy, want);
197
198				XSetErrorHandler(old_handler);
199				trapped_xerror = 0;
200			}
201		}
202	}
203#endif
204#endif
205}
206
207static void check_dpms(void) {
208	static int init_dpms = 0;
209#if LIBVNCSERVER_HAVE_DPMS
210	static int dpms_capable = 0;
211	static time_t last_dpms = 0;
212	int db = 0;
213
214	CARD16 level;
215	BOOL enabled;
216
217	RAWFB_RET_VOID
218
219	if (! init_dpms) {
220		if (getenv("DPMS_DEBUG")) {
221			db = atoi(getenv("DPMS_DEBUG"));
222		}
223		if (DPMSCapable(dpy)) {
224			dpms_capable = 1;
225			rfbLog("X display is capable of DPMS.\n");
226			if (watch_dpms) {
227				rfbLog("Preventing low-power DPMS modes when"
228				    " clients are connected.\n");
229			}
230		} else {
231			if (! raw_fb_str) {
232				rfbLog("X display is not capable of DPMS.\n");
233			}
234			dpms_capable = 0;
235		}
236		init_dpms = 1;
237	}
238
239	if (force_dpms || (client_dpms && client_count)) {
240		static int last_enable = 0;
241		if (time(NULL) > last_enable) {
242			set_dpms_mode("enable");
243			last_enable = time(NULL);
244		}
245		set_dpms_mode("off");
246	}
247	if (! watch_dpms) {
248		return;
249	}
250	if (! dpms_capable) {
251		return;
252	}
253	if (! client_count) {
254		return;
255	}
256	if (time(NULL) < last_dpms + 5) {
257		return;
258	}
259	last_dpms = time(NULL);
260
261	if (DPMSInfo(dpy, &level, &enabled)) {
262		if (db) fprintf(stderr, "DPMSInfo level: %d enabled: %d\n", level, enabled);
263
264		if (enabled && level != DPMSModeOn) {
265			char *from = "unknown-dpms-state";
266			XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
267			trapped_xerror = 0;
268
269			if (level == DPMSModeStandby) {
270				from = "DPMSModeStandby";
271			} else if (level == DPMSModeSuspend) {
272				from = "DPMSModeSuspend";
273			} else if (level == DPMSModeOff) {
274				from = "DPMSModeOff";
275			}
276
277			rfbLog("switching DPMS state from %s to DPMSModeOn\n", from);
278
279			DPMSForceLevel(dpy, DPMSModeOn);
280
281			XSetErrorHandler(old_handler);
282			trapped_xerror = 0;
283		}
284	} else {
285		if (db) fprintf(stderr, "DPMSInfo failed.\n");
286	}
287#else
288	RAWFB_RET_VOID
289	if (! init_dpms) {
290		if (! raw_fb_str) {
291			rfbLog("X DPMS extension not supported.\n");
292		}
293		init_dpms = 1;
294	}
295#endif
296}
297
298