1
2 package screensaver
3
4
5
6 import (
7 "github.com/jezek/xgb"
8
9 "github.com/jezek/xgb/xproto"
10 )
11
12
13 func Init(c *xgb.Conn) error {
14 reply, err := xproto.QueryExtension(c, 16, "MIT-SCREEN-SAVER").Reply()
15 switch {
16 case err != nil:
17 return err
18 case !reply.Present:
19 return xgb.Errorf("No extension named MIT-SCREEN-SAVER could be found on on the server.")
20 }
21
22 c.ExtLock.Lock()
23 c.Extensions["MIT-SCREEN-SAVER"] = reply.MajorOpcode
24 c.ExtLock.Unlock()
25 for evNum, fun := range xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"] {
26 xgb.NewEventFuncs[int(reply.FirstEvent)+evNum] = fun
27 }
28 for errNum, fun := range xgb.NewExtErrorFuncs["MIT-SCREEN-SAVER"] {
29 xgb.NewErrorFuncs[int(reply.FirstError)+errNum] = fun
30 }
31 return nil
32 }
33
34 func init() {
35 xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"] = make(map[int]xgb.NewEventFun)
36 xgb.NewExtErrorFuncs["MIT-SCREEN-SAVER"] = make(map[int]xgb.NewErrorFun)
37 }
38
39 const (
40 EventNotifyMask = 1
41 EventCycleMask = 2
42 )
43
44 const (
45 KindBlanked = 0
46 KindInternal = 1
47 KindExternal = 2
48 )
49
50
51 const Notify = 0
52
53 type NotifyEvent struct {
54 Sequence uint16
55 State byte
56 Time xproto.Timestamp
57 Root xproto.Window
58 Window xproto.Window
59 Kind byte
60 Forced bool
61
62 }
63
64
65 func NotifyEventNew(buf []byte) xgb.Event {
66 v := NotifyEvent{}
67 b := 1
68
69 v.State = buf[b]
70 b += 1
71
72 v.Sequence = xgb.Get16(buf[b:])
73 b += 2
74
75 v.Time = xproto.Timestamp(xgb.Get32(buf[b:]))
76 b += 4
77
78 v.Root = xproto.Window(xgb.Get32(buf[b:]))
79 b += 4
80
81 v.Window = xproto.Window(xgb.Get32(buf[b:]))
82 b += 4
83
84 v.Kind = buf[b]
85 b += 1
86
87 if buf[b] == 1 {
88 v.Forced = true
89 } else {
90 v.Forced = false
91 }
92 b += 1
93
94 b += 14
95
96 return v
97 }
98
99
100 func (v NotifyEvent) Bytes() []byte {
101 buf := make([]byte, 32)
102 b := 0
103
104
105 buf[b] = 0
106 b += 1
107
108 buf[b] = v.State
109 b += 1
110
111 b += 2
112
113 xgb.Put32(buf[b:], uint32(v.Time))
114 b += 4
115
116 xgb.Put32(buf[b:], uint32(v.Root))
117 b += 4
118
119 xgb.Put32(buf[b:], uint32(v.Window))
120 b += 4
121
122 buf[b] = v.Kind
123 b += 1
124
125 if v.Forced {
126 buf[b] = 1
127 } else {
128 buf[b] = 0
129 }
130 b += 1
131
132 b += 14
133
134 return buf
135 }
136
137
138
139
140 func (v NotifyEvent) SequenceId() uint16 {
141 return v.Sequence
142 }
143
144
145 func (v NotifyEvent) String() string {
146 fieldVals := make([]string, 0, 7)
147 fieldVals = append(fieldVals, xgb.Sprintf("Sequence: %d", v.Sequence))
148 fieldVals = append(fieldVals, xgb.Sprintf("State: %d", v.State))
149 fieldVals = append(fieldVals, xgb.Sprintf("Time: %d", v.Time))
150 fieldVals = append(fieldVals, xgb.Sprintf("Root: %d", v.Root))
151 fieldVals = append(fieldVals, xgb.Sprintf("Window: %d", v.Window))
152 fieldVals = append(fieldVals, xgb.Sprintf("Kind: %d", v.Kind))
153 fieldVals = append(fieldVals, xgb.Sprintf("Forced: %t", v.Forced))
154 return "Notify {" + xgb.StringsJoin(fieldVals, ", ") + "}"
155 }
156
157 func init() {
158 xgb.NewExtEventFuncs["MIT-SCREEN-SAVER"][0] = NotifyEventNew
159 }
160
161 const (
162 StateOff = 0
163 StateOn = 1
164 StateCycle = 2
165 StateDisabled = 3
166 )
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 type QueryInfoCookie struct {
194 *xgb.Cookie
195 }
196
197
198
199 func QueryInfo(c *xgb.Conn, Drawable xproto.Drawable) QueryInfoCookie {
200 c.ExtLock.RLock()
201 defer c.ExtLock.RUnlock()
202 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
203 panic("Cannot issue request 'QueryInfo' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
204 }
205 cookie := c.NewCookie(true, true)
206 c.NewRequest(queryInfoRequest(c, Drawable), cookie)
207 return QueryInfoCookie{cookie}
208 }
209
210
211
212 func QueryInfoUnchecked(c *xgb.Conn, Drawable xproto.Drawable) QueryInfoCookie {
213 c.ExtLock.RLock()
214 defer c.ExtLock.RUnlock()
215 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
216 panic("Cannot issue request 'QueryInfo' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
217 }
218 cookie := c.NewCookie(false, true)
219 c.NewRequest(queryInfoRequest(c, Drawable), cookie)
220 return QueryInfoCookie{cookie}
221 }
222
223
224 type QueryInfoReply struct {
225 Sequence uint16
226 Length uint32
227 State byte
228 SaverWindow xproto.Window
229 MsUntilServer uint32
230 MsSinceUserInput uint32
231 EventMask uint32
232 Kind byte
233
234 }
235
236
237 func (cook QueryInfoCookie) Reply() (*QueryInfoReply, error) {
238 buf, err := cook.Cookie.Reply()
239 if err != nil {
240 return nil, err
241 }
242 if buf == nil {
243 return nil, nil
244 }
245 return queryInfoReply(buf), nil
246 }
247
248
249 func queryInfoReply(buf []byte) *QueryInfoReply {
250 v := new(QueryInfoReply)
251 b := 1
252
253 v.State = buf[b]
254 b += 1
255
256 v.Sequence = xgb.Get16(buf[b:])
257 b += 2
258
259 v.Length = xgb.Get32(buf[b:])
260 b += 4
261
262 v.SaverWindow = xproto.Window(xgb.Get32(buf[b:]))
263 b += 4
264
265 v.MsUntilServer = xgb.Get32(buf[b:])
266 b += 4
267
268 v.MsSinceUserInput = xgb.Get32(buf[b:])
269 b += 4
270
271 v.EventMask = xgb.Get32(buf[b:])
272 b += 4
273
274 v.Kind = buf[b]
275 b += 1
276
277 b += 7
278
279 return v
280 }
281
282
283
284 func queryInfoRequest(c *xgb.Conn, Drawable xproto.Drawable) []byte {
285 size := 8
286 b := 0
287 buf := make([]byte, size)
288
289 c.ExtLock.RLock()
290 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
291 c.ExtLock.RUnlock()
292 b += 1
293
294 buf[b] = 1
295 b += 1
296
297 xgb.Put16(buf[b:], uint16(size/4))
298 b += 2
299
300 xgb.Put32(buf[b:], uint32(Drawable))
301 b += 4
302
303 return buf
304 }
305
306
307 type QueryVersionCookie struct {
308 *xgb.Cookie
309 }
310
311
312
313 func QueryVersion(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) QueryVersionCookie {
314 c.ExtLock.RLock()
315 defer c.ExtLock.RUnlock()
316 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
317 panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
318 }
319 cookie := c.NewCookie(true, true)
320 c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
321 return QueryVersionCookie{cookie}
322 }
323
324
325
326 func QueryVersionUnchecked(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) QueryVersionCookie {
327 c.ExtLock.RLock()
328 defer c.ExtLock.RUnlock()
329 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
330 panic("Cannot issue request 'QueryVersion' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
331 }
332 cookie := c.NewCookie(false, true)
333 c.NewRequest(queryVersionRequest(c, ClientMajorVersion, ClientMinorVersion), cookie)
334 return QueryVersionCookie{cookie}
335 }
336
337
338 type QueryVersionReply struct {
339 Sequence uint16
340 Length uint32
341
342 ServerMajorVersion uint16
343 ServerMinorVersion uint16
344
345 }
346
347
348 func (cook QueryVersionCookie) Reply() (*QueryVersionReply, error) {
349 buf, err := cook.Cookie.Reply()
350 if err != nil {
351 return nil, err
352 }
353 if buf == nil {
354 return nil, nil
355 }
356 return queryVersionReply(buf), nil
357 }
358
359
360 func queryVersionReply(buf []byte) *QueryVersionReply {
361 v := new(QueryVersionReply)
362 b := 1
363
364 b += 1
365
366 v.Sequence = xgb.Get16(buf[b:])
367 b += 2
368
369 v.Length = xgb.Get32(buf[b:])
370 b += 4
371
372 v.ServerMajorVersion = xgb.Get16(buf[b:])
373 b += 2
374
375 v.ServerMinorVersion = xgb.Get16(buf[b:])
376 b += 2
377
378 b += 20
379
380 return v
381 }
382
383
384
385 func queryVersionRequest(c *xgb.Conn, ClientMajorVersion byte, ClientMinorVersion byte) []byte {
386 size := 8
387 b := 0
388 buf := make([]byte, size)
389
390 c.ExtLock.RLock()
391 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
392 c.ExtLock.RUnlock()
393 b += 1
394
395 buf[b] = 0
396 b += 1
397
398 xgb.Put16(buf[b:], uint16(size/4))
399 b += 2
400
401 buf[b] = ClientMajorVersion
402 b += 1
403
404 buf[b] = ClientMinorVersion
405 b += 1
406
407 b += 2
408
409 return buf
410 }
411
412
413 type SelectInputCookie struct {
414 *xgb.Cookie
415 }
416
417
418
419 func SelectInput(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) SelectInputCookie {
420 c.ExtLock.RLock()
421 defer c.ExtLock.RUnlock()
422 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
423 panic("Cannot issue request 'SelectInput' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
424 }
425 cookie := c.NewCookie(false, false)
426 c.NewRequest(selectInputRequest(c, Drawable, EventMask), cookie)
427 return SelectInputCookie{cookie}
428 }
429
430
431
432 func SelectInputChecked(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) SelectInputCookie {
433 c.ExtLock.RLock()
434 defer c.ExtLock.RUnlock()
435 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
436 panic("Cannot issue request 'SelectInput' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
437 }
438 cookie := c.NewCookie(true, false)
439 c.NewRequest(selectInputRequest(c, Drawable, EventMask), cookie)
440 return SelectInputCookie{cookie}
441 }
442
443
444
445 func (cook SelectInputCookie) Check() error {
446 return cook.Cookie.Check()
447 }
448
449
450
451 func selectInputRequest(c *xgb.Conn, Drawable xproto.Drawable, EventMask uint32) []byte {
452 size := 12
453 b := 0
454 buf := make([]byte, size)
455
456 c.ExtLock.RLock()
457 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
458 c.ExtLock.RUnlock()
459 b += 1
460
461 buf[b] = 2
462 b += 1
463
464 xgb.Put16(buf[b:], uint16(size/4))
465 b += 2
466
467 xgb.Put32(buf[b:], uint32(Drawable))
468 b += 4
469
470 xgb.Put32(buf[b:], EventMask)
471 b += 4
472
473 return buf
474 }
475
476
477 type SetAttributesCookie struct {
478 *xgb.Cookie
479 }
480
481
482
483 func SetAttributes(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) SetAttributesCookie {
484 c.ExtLock.RLock()
485 defer c.ExtLock.RUnlock()
486 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
487 panic("Cannot issue request 'SetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
488 }
489 cookie := c.NewCookie(false, false)
490 c.NewRequest(setAttributesRequest(c, Drawable, X, Y, Width, Height, BorderWidth, Class, Depth, Visual, ValueMask, ValueList), cookie)
491 return SetAttributesCookie{cookie}
492 }
493
494
495
496 func SetAttributesChecked(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) SetAttributesCookie {
497 c.ExtLock.RLock()
498 defer c.ExtLock.RUnlock()
499 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
500 panic("Cannot issue request 'SetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
501 }
502 cookie := c.NewCookie(true, false)
503 c.NewRequest(setAttributesRequest(c, Drawable, X, Y, Width, Height, BorderWidth, Class, Depth, Visual, ValueMask, ValueList), cookie)
504 return SetAttributesCookie{cookie}
505 }
506
507
508
509 func (cook SetAttributesCookie) Check() error {
510 return cook.Cookie.Check()
511 }
512
513
514
515 func setAttributesRequest(c *xgb.Conn, Drawable xproto.Drawable, X int16, Y int16, Width uint16, Height uint16, BorderWidth uint16, Class byte, Depth byte, Visual xproto.Visualid, ValueMask uint32, ValueList []uint32) []byte {
516 size := xgb.Pad((24 + (4 + xgb.Pad((4 * xgb.PopCount(int(ValueMask)))))))
517 b := 0
518 buf := make([]byte, size)
519
520 c.ExtLock.RLock()
521 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
522 c.ExtLock.RUnlock()
523 b += 1
524
525 buf[b] = 3
526 b += 1
527
528 xgb.Put16(buf[b:], uint16(size/4))
529 b += 2
530
531 xgb.Put32(buf[b:], uint32(Drawable))
532 b += 4
533
534 xgb.Put16(buf[b:], uint16(X))
535 b += 2
536
537 xgb.Put16(buf[b:], uint16(Y))
538 b += 2
539
540 xgb.Put16(buf[b:], Width)
541 b += 2
542
543 xgb.Put16(buf[b:], Height)
544 b += 2
545
546 xgb.Put16(buf[b:], BorderWidth)
547 b += 2
548
549 buf[b] = Class
550 b += 1
551
552 buf[b] = Depth
553 b += 1
554
555 xgb.Put32(buf[b:], uint32(Visual))
556 b += 4
557
558 xgb.Put32(buf[b:], ValueMask)
559 b += 4
560 for i := 0; i < xgb.PopCount(int(ValueMask)); i++ {
561 xgb.Put32(buf[b:], ValueList[i])
562 b += 4
563 }
564 b = xgb.Pad(b)
565
566 return buf
567 }
568
569
570 type SuspendCookie struct {
571 *xgb.Cookie
572 }
573
574
575
576 func Suspend(c *xgb.Conn, Suspend bool) SuspendCookie {
577 c.ExtLock.RLock()
578 defer c.ExtLock.RUnlock()
579 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
580 panic("Cannot issue request 'Suspend' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
581 }
582 cookie := c.NewCookie(false, false)
583 c.NewRequest(suspendRequest(c, Suspend), cookie)
584 return SuspendCookie{cookie}
585 }
586
587
588
589 func SuspendChecked(c *xgb.Conn, Suspend bool) SuspendCookie {
590 c.ExtLock.RLock()
591 defer c.ExtLock.RUnlock()
592 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
593 panic("Cannot issue request 'Suspend' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
594 }
595 cookie := c.NewCookie(true, false)
596 c.NewRequest(suspendRequest(c, Suspend), cookie)
597 return SuspendCookie{cookie}
598 }
599
600
601
602 func (cook SuspendCookie) Check() error {
603 return cook.Cookie.Check()
604 }
605
606
607
608 func suspendRequest(c *xgb.Conn, Suspend bool) []byte {
609 size := 8
610 b := 0
611 buf := make([]byte, size)
612
613 c.ExtLock.RLock()
614 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
615 c.ExtLock.RUnlock()
616 b += 1
617
618 buf[b] = 5
619 b += 1
620
621 xgb.Put16(buf[b:], uint16(size/4))
622 b += 2
623
624 if Suspend {
625 buf[b] = 1
626 } else {
627 buf[b] = 0
628 }
629 b += 1
630
631 b += 3
632
633 return buf
634 }
635
636
637 type UnsetAttributesCookie struct {
638 *xgb.Cookie
639 }
640
641
642
643 func UnsetAttributes(c *xgb.Conn, Drawable xproto.Drawable) UnsetAttributesCookie {
644 c.ExtLock.RLock()
645 defer c.ExtLock.RUnlock()
646 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
647 panic("Cannot issue request 'UnsetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
648 }
649 cookie := c.NewCookie(false, false)
650 c.NewRequest(unsetAttributesRequest(c, Drawable), cookie)
651 return UnsetAttributesCookie{cookie}
652 }
653
654
655
656 func UnsetAttributesChecked(c *xgb.Conn, Drawable xproto.Drawable) UnsetAttributesCookie {
657 c.ExtLock.RLock()
658 defer c.ExtLock.RUnlock()
659 if _, ok := c.Extensions["MIT-SCREEN-SAVER"]; !ok {
660 panic("Cannot issue request 'UnsetAttributes' using the uninitialized extension 'MIT-SCREEN-SAVER'. screensaver.Init(connObj) must be called first.")
661 }
662 cookie := c.NewCookie(true, false)
663 c.NewRequest(unsetAttributesRequest(c, Drawable), cookie)
664 return UnsetAttributesCookie{cookie}
665 }
666
667
668
669 func (cook UnsetAttributesCookie) Check() error {
670 return cook.Cookie.Check()
671 }
672
673
674
675 func unsetAttributesRequest(c *xgb.Conn, Drawable xproto.Drawable) []byte {
676 size := 8
677 b := 0
678 buf := make([]byte, size)
679
680 c.ExtLock.RLock()
681 buf[b] = c.Extensions["MIT-SCREEN-SAVER"]
682 c.ExtLock.RUnlock()
683 b += 1
684
685 buf[b] = 4
686 b += 1
687
688 xgb.Put16(buf[b:], uint16(size/4))
689 b += 2
690
691 xgb.Put32(buf[b:], uint32(Drawable))
692 b += 4
693
694 return buf
695 }
696
View as plain text