Skip to content

Commit 1427cfa

Browse files
Merge pull request #169 from thiagokokada/add-dpms-extension
Add DPMS extension
2 parents 2dbeb64 + b484fc1 commit 1427cfa

File tree

3 files changed

+313
-0
lines changed

3 files changed

+313
-0
lines changed

Xlib/ext/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
('XInputExtension', 'xinput'),
3939
('NV-CONTROL', 'nvcontrol'),
4040
('DAMAGE', 'damage'),
41+
('DPMS', 'dpms'),
4142
]
4243

4344
__all__ = map(lambda x: x[1], __extensions__)

Xlib/ext/dpms.py

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
# Xlib.ext.dpms -- X Display Power Management Signaling
2+
#
3+
# Copyright (C) 2020 Thiago Kenji Okada <thiagokada@gmail.com>
4+
#
5+
# This library is free software; you can redistribute it and/or
6+
# modify it under the terms of the GNU Lesser General Public License
7+
# as published by the Free Software Foundation; either version 2.1
8+
# of the License, or (at your option) any later version.
9+
#
10+
# This library is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13+
# See the GNU Lesser General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU Lesser General Public
16+
# License along with this library; if not, write to the
17+
# Free Software Foundation, Inc.,
18+
# 59 Temple Place,
19+
# Suite 330,
20+
# Boston, MA 02111-1307 USA
21+
22+
'''
23+
This extension provides X Protocol control over the VESA Display
24+
Power Management Signaling (DPMS) characteristics of video boards
25+
under control of the X Window System.
26+
27+
Documentation: https://www.x.org/releases/X11R7.7/doc/xextproto/dpms.html
28+
'''
29+
30+
from Xlib import X
31+
from Xlib.protocol import rq
32+
33+
extname = 'DPMS'
34+
35+
36+
# DPMS Extension Power Levels
37+
# 0 DPMSModeOn In use
38+
# 1 DPMSModeStandby Blanked, low power
39+
# 2 DPMSModeSuspend Blanked, lower power
40+
# 3 DPMSModeOff Shut off, awaiting activity
41+
DPMSModeOn = 0
42+
DPMSModeStandby = 1
43+
DPMSModeSuspend = 2
44+
DPMSModeOff = 3
45+
46+
DPMSPowerLevel = (
47+
DPMSModeOn,
48+
DPMSModeStandby,
49+
DPMSModeSuspend,
50+
DPMSModeOff,
51+
)
52+
53+
54+
class DPMSGetVersion(rq.ReplyRequest):
55+
_request = rq.Struct(
56+
rq.Card8('opcode'),
57+
rq.Opcode(0),
58+
rq.RequestLength(),
59+
rq.Card16('major_version'),
60+
rq.Card16('minor_version'),
61+
)
62+
63+
_reply = rq.Struct(
64+
rq.ReplyCode(),
65+
rq.Pad(1),
66+
rq.Card16('sequence_number'),
67+
rq.ReplyLength(),
68+
rq.Card16('major_version'),
69+
rq.Card16('minor_version'),
70+
rq.Pad(20),
71+
)
72+
73+
74+
def get_version(self):
75+
return DPMSGetVersion(display=self.display,
76+
opcode=self.display.get_extension_major(extname),
77+
major_version=1,
78+
minor_version=1)
79+
80+
81+
class DPMSCapable(rq.ReplyRequest):
82+
_request = rq.Struct(
83+
rq.Card8('opcode'),
84+
rq.Opcode(1),
85+
rq.RequestLength(),
86+
)
87+
88+
_reply = rq.Struct(
89+
rq.ReplyCode(),
90+
rq.Pad(1),
91+
rq.Card16('sequence_number'),
92+
rq.ReplyLength(),
93+
rq.Bool('capable'),
94+
rq.Pad(23),
95+
)
96+
97+
98+
def capable(self):
99+
return DPMSCapable(display=self.display,
100+
opcode=self.display.get_extension_major(extname),
101+
major_version=1,
102+
minor_version=1)
103+
104+
105+
class DPMSGetTimeouts(rq.ReplyRequest):
106+
_request = rq.Struct(
107+
rq.Card8('opcode'),
108+
rq.Opcode(2),
109+
rq.RequestLength(),
110+
)
111+
112+
_reply = rq.Struct(
113+
rq.ReplyCode(),
114+
rq.Pad(1),
115+
rq.Card16('sequence_number'),
116+
rq.ReplyLength(),
117+
rq.Card16('standby_timeout'),
118+
rq.Card16('suspend_timeout'),
119+
rq.Card16('off_timeout'),
120+
rq.Pad(18),
121+
)
122+
123+
124+
def get_timeouts(self):
125+
return DPMSGetTimeouts(display=self.display,
126+
opcode=self.display.get_extension_major(extname),
127+
major_version=1,
128+
minor_version=1)
129+
130+
131+
class DPMSSetTimeouts(rq.Request):
132+
_request = rq.Struct(
133+
rq.Card8('opcode'),
134+
rq.Opcode(3),
135+
rq.RequestLength(),
136+
rq.Card16('standby_timeout'),
137+
rq.Card16('suspend_timeout'),
138+
rq.Card16('off_timeout'),
139+
rq.Pad(2)
140+
)
141+
142+
143+
def set_timeouts(self, standby_timeout, suspend_timeout, off_timeout):
144+
return DPMSSetTimeouts(display=self.display,
145+
opcode=self.display.get_extension_major(extname),
146+
major_version=1,
147+
minor_version=1,
148+
standby_timeout=standby_timeout,
149+
suspend_timeout=suspend_timeout,
150+
off_timeout=off_timeout)
151+
152+
153+
class DPMSEnable(rq.Request):
154+
_request = rq.Struct(
155+
rq.Card8('opcode'),
156+
rq.Opcode(4),
157+
rq.RequestLength(),
158+
)
159+
160+
161+
def enable(self):
162+
return DPMSEnable(display=self.display,
163+
opcode=self.display.get_extension_major(extname),
164+
major_version=1,
165+
minor_version=1)
166+
167+
168+
class DPMSDisable(rq.Request):
169+
_request = rq.Struct(
170+
rq.Card8('opcode'),
171+
rq.Opcode(5),
172+
rq.RequestLength(),
173+
)
174+
175+
176+
def disable(self):
177+
return DPMSDisable(display=self.display,
178+
opcode=self.display.get_extension_major(extname),
179+
major_version=1,
180+
minor_version=1)
181+
182+
183+
class DPMSForceLevel(rq.Request):
184+
_request = rq.Struct(
185+
rq.Card8('opcode'),
186+
rq.Opcode(6),
187+
rq.RequestLength(),
188+
rq.Resource('power_level', DPMSPowerLevel),
189+
)
190+
191+
192+
def force_level(self, power_level):
193+
return DPMSForceLevel(display=self.display,
194+
opcode=self.display.get_extension_major(extname),
195+
major_version=1,
196+
minor_version=1,
197+
power_level=power_level)
198+
199+
200+
class DPMSInfo(rq.ReplyRequest):
201+
_request = rq.Struct(
202+
rq.Card8('opcode'),
203+
rq.Opcode(7),
204+
rq.RequestLength(),
205+
)
206+
207+
_reply = rq.Struct(
208+
rq.ReplyCode(),
209+
rq.Pad(1),
210+
rq.Card16('sequence_number'),
211+
rq.ReplyLength(),
212+
rq.Resource('power_level', DPMSPowerLevel),
213+
rq.Bool('state'),
214+
rq.Pad(21),
215+
)
216+
217+
218+
def info(self):
219+
return DPMSInfo(display=self.display,
220+
opcode=self.display.get_extension_major(extname),
221+
major_version=1,
222+
minor_version=1)
223+
224+
225+
def init(disp, info):
226+
disp.extension_add_method('display', 'dpms_get_version', get_version)
227+
disp.extension_add_method('display', 'dpms_capable', capable)
228+
disp.extension_add_method('display', 'dpms_get_timeouts', get_timeouts)
229+
disp.extension_add_method('display', 'dpms_set_timeouts', set_timeouts)
230+
disp.extension_add_method('display', 'dpms_enable', enable)
231+
disp.extension_add_method('display', 'dpms_disable', disable)
232+
disp.extension_add_method('display', 'dpms_force_level', force_level)
233+
# TODO: Returns 'TypeError: first argument must be callable' on call
234+
# disp.extension_add_method('display', 'dpms_info', info)

examples/dpms.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/python
2+
#
3+
# examples/dpms.py -- DPMS usage examples.
4+
#
5+
# Copyright (C) 2020 Thiago Kenji Okada<thiagokokada@gmail.com>
6+
#
7+
# This library is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU Lesser General Public License
9+
# as published by the Free Software Foundation; either version 2.1
10+
# of the License, or (at your option) any later version.
11+
#
12+
# This library 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.
15+
# See the GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public
18+
# License along with this library; if not, write to the
19+
# Free Software Foundation, Inc.,
20+
# 59 Temple Place,
21+
# Suite 330,
22+
# Boston, MA 02111-1307 USA
23+
24+
import time
25+
26+
from Xlib import display
27+
from Xlib.ext import dpms
28+
29+
30+
class DPMSExamples(object):
31+
def __init__(self):
32+
self.d = display.Display()
33+
# Making sure that DPMS is enabled
34+
self.d.dpms_enable()
35+
# For some reason, the call above needs another X11 call
36+
# to actually trigger it
37+
self.d.dpms_get_version()
38+
39+
def dpms_info(self):
40+
capable = self.d.dpms_capable()
41+
timeouts = self.d.dpms_get_timeouts()
42+
43+
return (capable, timeouts)
44+
45+
def turn_off_display(self):
46+
self.d.dpms_force_level(dpms.DPMSModeOff)
47+
# For some reason, the call above needs another X11 call
48+
# to actually trigger it
49+
self.d.dpms_get_version()
50+
51+
def turn_on_display(self):
52+
self.d.dpms_force_level(dpms.DPMSModeOn)
53+
# For some reason, the call above needs another X11 call
54+
# to actually trigger it
55+
self.d.dpms_get_version()
56+
57+
58+
if __name__ == '__main__':
59+
examples = DPMSExamples()
60+
61+
capable, timeouts = examples.dpms_info()
62+
63+
assert capable, 'DPMS is not supported in your system'
64+
65+
print('Current DPMS timeouts:')
66+
print('Standby: {}, Suspend: {}, Off: {}'.format(
67+
timeouts.standby_timeout,
68+
timeouts.suspend_timeout,
69+
timeouts.off_timeout
70+
))
71+
72+
print('\nThe next example will turn-off your screen, press Ctrl-C to cancel.')
73+
time.sleep(2)
74+
examples.turn_off_display()
75+
76+
print('\nTurning it on again...')
77+
time.sleep(2)
78+
examples.turn_on_display()

0 commit comments

Comments
 (0)