Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com>
      3    All rights reserved.
      4 
      5 This file is part of x11vnc.
      6 
      7 x11vnc is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2 of the License, or (at
     10 your option) any later version.
     11 
     12 x11vnc is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with x11vnc; if not, write to the Free Software
     19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     20 or see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, as a special exception, Karl J. Runge
     23 gives permission to link the code of its release of x11vnc with the
     24 OpenSSL project's "OpenSSL" library (or with modified versions of it
     25 that use the same license as the "OpenSSL" library), and distribute
     26 the linked executables.  You must obey the GNU General Public License
     27 in all respects for all of the code used other than "OpenSSL".  If you
     28 modify this file, you may extend this exception to your version of the
     29 file, but you are not obligated to do so.  If you do not wish to do
     30 so, delete this exception statement from your version.
     31 */
     32 
     33 /* -- pm.c -- */
     34 #include "x11vnc.h"
     35 #include "cleanup.h"
     36 
     37 void check_pm(void);
     38 void set_dpms_mode(char *mode);
     39 static void check_fbpm(void);
     40 static 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 
     51 void 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 
     67 static 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 
    150 void 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 
    207 static 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