1#!/bin/sh 2#--------------------------------------------- 3# xdg-screensaver 4# 5# Utility script to control screensaver. 6# 7# Refer to the usage() function below for usage. 8# 9# Copyright 2006, Bryce Harrington <bryce@osdl.org> 10# 11# LICENSE: 12# 13#--------------------------------------------- 14 15manualpage() 16{ 17cat << _MANUALPAGE 18_MANUALPAGE 19} 20 21usage() 22{ 23cat << _USAGE 24_USAGE 25} 26 27#@xdg-utils-common@ 28 29# Check if we can use "mv -T" 30if mv -T ... ... 2>&1 | grep '\.\.\.' > /dev/null ; then 31 # We can securely move files in /tmp with mv -T 32 DEBUG 1 "mv -T available" 33 MV="mv -T" 34 screensaver_file="/tmp/xdg-screensaver-$USER-"`echo $DISPLAY | sed 's/:/-/g'` 35else 36 # No secure moves available, use home dir 37 DEBUG 1 "mv -T not available" 38 MV="mv" 39 screensaver_file="$HOME/.xdg-screensaver-"`echo $(hostname)-$DISPLAY | sed 's/:/-/g'` 40fi 41lockfile_command=`which lockfile 2> /dev/null` 42 43lockfile() 44{ 45 if [ -n "$lockfile_command" ] ; then 46 $lockfile_command -1 -l 10 -s 3 "$screensaver_file".lock 47 else 48 # Poor man's attempt at doing a lockfile 49 # Be careful not to facilitate a symlink attack 50 local try 51 try=0 52 while ! ln -s "$screensaver_file".lock "$screensaver_file".lock 2> /dev/null; 53 do 54 sleep 1 55 try=$(($try+1)) 56 if [ $try -eq 3 ] ; then 57 rm -f "$screensaver_file".lock || return # Can't remove lockfile 58 try=0 59 fi 60 done 61 fi 62} 63 64unlockfile() 65{ 66 rm -f "$screensaver_file".lock 67} 68 69perform_action() 70{ 71 result=1 72 73 if [ "$1" = "resume" ] ; then 74 # Restore DPMS state 75 if [ -f "$screensaver_file.dpms" ]; then 76 rm "$screensaver_file.dpms" 77 # Re-enable DPMS 78 xset +dpms 79 fi 80 fi 81 if [ "$1" = "reset" ] ; then 82 if xset -q | grep 'DPMS is Enabled' > /dev/null 2> /dev/null; then 83 xset dpms force on 84 fi 85 fi 86 87 case "$DE" in 88 kde) 89 if [ x"$KDE_SESSION_VERSION" = x"4" ]; then 90 screensaver_freedesktop "$1" 91 else 92 screensaver_kde "$1" 93 fi 94 ;; 95 96 gnome_screensaver) 97 screensaver_gnome_screensaver "$1" 98 ;; 99 100 xscreensaver) 101 screensaver_xscreensaver "$1" 102 ;; 103 104 '') 105 screensaver_xserver "$1" 106 ;; 107 esac 108 109 if [ "$1" = "suspend" ] ; then 110 # Save DPMS state 111 if xset -q | grep 'DPMS is Enabled' > /dev/null 2> /dev/null; then 112 test "${TMPDIR+set}" = set || TMPDIR=/tmp 113 tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX` 114 $MV "$tmpfile" "$screensaver_file.dpms" 115 # Disable DPMS 116 xset -dpms 117 fi 118 fi 119 120} 121 122cleanup_suspend() 123{ 124 lockfile 125 test "${TMPDIR+set}" = set || TMPDIR=/tmp 126 tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX` 127 grep -v "$window_id:$xprop_pid\$" "$screensaver_file" > "$tmpfile" 2> /dev/null 128 $MV "$tmpfile" "$screensaver_file" 129 if [ ! -s "$screensaver_file" ] ; then 130 rm "$screensaver_file" 131 unlockfile 132 # $screensaver_file is empty, do resume 133 perform_action resume 134 else 135 unlockfile 136 fi 137} 138 139do_resume() 140{ 141 lockfile # Obtain lockfile 142 # Find the PID of the trackingprocess 143 xprop_pid=`grep "$window_id:" "$screensaver_file" 2> /dev/null | cut -d ':' -f 2` 144 unlockfile # Free lockfile 145 if [ -n "$xprop_pid" ] && ps -p "$xprop_pid" 2> /dev/null | grep xprop > /dev/null; then 146 # Kill the tracking process 147 kill -s TERM $xprop_pid 148 fi 149 cleanup_suspend 150} 151 152XPROP=`which xprop 2> /dev/null` 153 154check_window_id() 155{ 156 if [ -z "$XPROP" ]; then 157 DEBUG 3 "xprop not found" 158 return 159 fi 160 DEBUG 2 "Running $XPROP -id $window_id" 161 if $XPROP -id $window_id > /dev/null 2> /dev/null; then 162 DEBUG 3 Window $window_id exists 163 else 164 DEBUG 3 Window $window_id does not exist 165 exit_failure_operation_failed "Window $window_id does not exist" 166 fi 167} 168 169track_window() 170{ 171 if [ -z "$XPROP" ]; then 172 # Don't track window if we don't have xprop 173 return 174 fi 175 lockfile 176 177 test "${TMPDIR+set}" = set || TMPDIR=/tmp 178 tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX` 179 # Filter stale entries from the xdg-screensaver status file 180 # Return if $window_id is being tracked already 181 ( 182 already_tracked=1 183 IFS_save="$IFS" 184 IFS=":" 185 while read wid pid; do 186 if ps -p "$pid" 2> /dev/null | grep xprop > /dev/null; then 187 echo "$wid:$pid" 188 if [ $wid = $window_id ] ; then 189 already_tracked=0 190 fi 191 fi 192 done 193 IFS="$IFS_save" 194 exit $already_tracked 195 ) < $screensaver_file > $tmpfile 196 already_tracked=$? 197 198 if [ "$already_tracked" -eq "0" ] ; then 199 $MV "$tmpfile" "$screensaver_file" 200 # We are already tracking $window_id, don't do anything 201 unlockfile 202 return 203 fi 204 205 # Start tracking $window_id 206 $XPROP -id $window_id -spy > /dev/null & 207 xprop_pid=$! 208 # Add window_id and xprop_pid to the xdg-screensave status file 209 echo "$window_id:$xprop_pid" >> $tmpfile 210 $MV "$tmpfile" "$screensaver_file" 211 unlockfile 212 # Wait for xprop to edit, it means that the window disappeared 213 wait $xprop_pid 214 # Clean up the administration and resume the screensaver 215 cleanup_suspend 216} 217 218screensaver_freedesktop() 219{ 220 case "$1" in 221 suspend) 222 dbus-send --session \ 223 --dest=org.freedesktop.ScreenSaver \ 224 --type=method_call \ 225 --print-reply \ 226 --reply-timeout=2000 \ 227 /ScreenSaver \ 228 org.freedesktop.ScreenSaver.Inhibit \ 229 string:$window_id \ 230 string:xdg-screensaver \ 231 | grep uint32 | cut -d ' ' -f 5 >| "$screensaver_file.cookie" \ 232 2> /dev/null 233 result=$? 234 ;; 235 236 resume) 237 if [ -f "$screensaver_file.cookie" ] ; then 238 value=`cat "$screensaver_file.cookie"` 239 dbus-send --session \ 240 --dest=org.freedesktop.ScreenSaver \ 241 --type=method_call \ 242 /ScreenSaver \ 243 org.freedesktop.ScreenSaver.UnInhibit \ 244 uint32:$value \ 245 2> /dev/null 246 rm -f "$screensaver_file.cookie" 247 fi 248 result=$? 249 ;; 250 251 activate) 252 dbus-send --session \ 253 --dest=org.freedesktop.ScreenSaver \ 254 --type=method_call \ 255 /ScreenSaver \ 256 org.freedesktop.ScreenSaver.SetActive \ 257 boolean:true \ 258 2> /dev/null 259 result=$? 260 ;; 261 262 lock) 263 dbus-send --session \ 264 --dest=org.freedesktop.ScreenSaver \ 265 --type=method_call \ 266 /ScreenSaver \ 267 org.freedesktop.ScreenSaver.Lock \ 268 2> /dev/null 269 ;; 270 271 reset) 272 if [ -f "$screensaver_file.cookie" ] ; then 273 value=`cat "$screensaver_file.cookie"` 274 dbus-send --session \ 275 --dest=org.freedesktop.ScreenSaver \ 276 --type=method_call \ 277 /ScreenSaver \ 278 org.freedesktop.ScreenSaver.UnInhibit \ 279 uint32:$value \ 280 2> /dev/null 281 rm -f "$screensaver_file.cookie" 282 fi 283 result=$? 284 ;; 285 286 status) 287 status=`dbus-send --session \ 288 --dest=org.freedesktop.ScreenSaver \ 289 --type=method_call \ 290 --print-reply \ 291 --reply-timeout=2000 \ 292 /ScreenSaver \ 293 org.freedesktop.ScreenSaver.GetActive \ 294 | grep boolean | cut -d ' ' -f 5` 295 result=$? 296 if [ x"$status" = "xtrue" ]; then 297 echo "enabled" 298 elif [ x"$status" = "xfalse" ]; then 299 echo "disabled" 300 else 301 echo "ERROR: dbus org.freedesktop.ScreenSaver.GetActive returned '$status'" >&2 302 return 1 303 fi 304 ;; 305 306 *) 307 echo "ERROR: Unknown command '$1'" >&2 308 return 1 309 ;; 310 esac 311} 312 313screensaver_kde() 314{ 315 case "$1" in 316 suspend) 317 dcop kdesktop KScreensaverIface enable false > /dev/null 318 result=$? 319 ;; 320 321 resume) 322 dcop kdesktop KScreensaverIface configure > /dev/null 323 result=$? 324 ;; 325 326 activate) 327 dcop kdesktop KScreensaverIface save > /dev/null 328 result=$? 329 ;; 330 331 lock) 332 dcop kdesktop KScreensaverIface lock > /dev/null 333 result=$? 334 ;; 335 336 reset) 337 # Turns the screensaver off right now 338 dcop kdesktop KScreensaverIface quit > /dev/null 339 result=$? 340 ;; 341 342 status) 343 status=`dcop kdesktop KScreensaverIface isEnabled` 344 result=$? 345 if [ x"$status" = "xtrue" ]; then 346 echo "enabled" 347 elif [ x"$status" = "xfalse" ]; then 348 echo "disabled" 349 else 350 echo "ERROR: kdesktop KScreensaverIface isEnabled returned '$status'" >&2 351 return 1 352 fi 353 ;; 354 355 *) 356 echo "ERROR: Unknown command '$1'" >&2 357 return 1 358 ;; 359 esac 360} 361 362screensaver_xserver() 363{ 364 case "$1" in 365 suspend) 366 xset s off > /dev/null 367 result=$? 368 ;; 369 370 resume) 371 xset s default > /dev/null 372 result=$? 373 ;; 374 375 activate) 376 xset s activate > /dev/null 377 result=$? 378 ;; 379 380 reset) 381 xset s reset > /dev/null 382 result=$? 383 ;; 384 385 status) 386 timeout=`xset q | sed '/^Screen Saver:/,/^[^ ]/ { s/.*timeout: *\([0-9]*\).*/\1/; t }; d'` 387 result=$? 388 if [ "$timeout" -gt 0 ]; then 389 echo "enabled" 390 elif [ "$timeout" -eq 0 ]; then 391 echo "disabled" 392 else 393 echo "ERROR: xset q did not report the screensaver timeout" >&2 394 return 1 395 fi 396 ;; 397 398 *) 399 echo "ERROR: Unknown command '$1'" >&2 400 return 1 401 ;; 402 esac 403} 404 405screensaver_suspend_loop() 406{ 407 lockfile 408 test "${TMPDIR+set}" = set || TMPDIR=/tmp 409 tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX` 410 # Filter stale entries from the xdg-screensaver status file 411 cat "$screensaver_file" 2> /dev/null | ( 412 IFS_save="$IFS" 413 IFS=":" 414 while read wid pid; do 415 if ps -p "$pid" 2> /dev/null | grep xprop > /dev/null; then 416 echo "$wid:$pid" 417 fi 418 done 419 IFS="$IFS_save" 420 ) > $tmpfile 421 if [ -s "$tmpfile" ] ; then 422 # Suspend pending, don't do a thing 423 $MV "$tmpfile" "$screensaver_file" 424 unlockfile 425 return 426 fi 427 $MV "$tmpfile" "$screensaver_file" 428 unlockfile 429 (while [ -f "$screensaver_file" ]; do $*; sleep 50; done) > /dev/null 2> /dev/null & 430} 431 432screensaver_gnome_screensaver() 433{ 434# DBUS interface for gnome-screensaver 435# http://people.gnome.org/~mccann/gnome-screensaver/docs/gnome-screensaver.html 436 case "$1" in 437 suspend) 438 screensaver_suspend_loop \ 439 dbus-send --session \ 440 --dest=org.gnome.ScreenSaver \ 441 --type=method_call \ 442 /org/gnome/ScreenSaver \ 443 org.gnome.ScreenSaver.SimulateUserActivity \ 444 2> /dev/null 445 result=$? 446 ;; 447 448 resume) 449 # Automatic resume when $screensaver_file disappears 450 result=0 451 ;; 452 453 activate) 454 dbus-send --session \ 455 --dest=org.gnome.ScreenSaver \ 456 --type=method_call \ 457 /org/gnome/ScreenSaver \ 458 org.gnome.ScreenSaver.SetActive \ 459 boolean:true \ 460 2> /dev/null 461 result=$? 462 ;; 463 464 lock) 465 gnome-screensaver-command --lock > /dev/null 2> /dev/null 466 result=$? 467 ;; 468 469 reset) 470 # Turns the screensaver off right now 471 dbus-send --session \ 472 --dest=org.gnome.ScreenSaver \ 473 --type=method_call \ 474 /org/gnome/ScreenSaver \ 475 org.gnome.ScreenSaver.SimulateUserActivity \ 476 2> /dev/null 477 result=$? 478 ;; 479 480 status) 481 status=`dbus-send --session \ 482 --dest=org.gnome.ScreenSaver \ 483 --type=method_call \ 484 --print-reply \ 485 --reply-timeout=2000 \ 486 /org/gnome/ScreenSaver \ 487 org.gnome.ScreenSaver.GetActive \ 488 | grep boolean | cut -d ' ' -f 5` 489 result=$? 490 if [ x"$status" = "xtrue" -o x"$status" = "xfalse" ]; then 491 echo "enabled" 492 elif [ x"$result" != "x0" ]; then 493 echo "ERROR: dbus org.gnome.ScreenSaver.GetActive returned '$status'" >&2 494 return 1 495 else 496 echo "disabled" 497 fi 498 ;; 499 500 *) 501 echo "ERROR: Unknown command '$1" >&2 502 return 1 503 ;; 504 esac 505} 506 507screensaver_xscreensaver() 508{ 509 case "$1" in 510 suspend) 511 screensaver_suspend_loop xscreensaver-command -deactivate 512 result=0 513 ;; 514 515 resume) 516 # Automatic resume when $screensaver_file disappears 517 result=0 518 ;; 519 520 activate) 521 xscreensaver-command -activate > /dev/null 2> /dev/null 522 result=$? 523 ;; 524 525 lock) 526 xscreensaver-command -lock > /dev/null 2> /dev/null 527 result=$? 528 ;; 529 530 reset) 531 # Turns the screensaver off right now 532 xscreensaver-command -deactivate > /dev/null 2> /dev/null 533 result=$? 534 ;; 535 536 status) 537 result=0 538 if [ -f "$screensaver_file" ] ; then 539 echo "disabled" 540 else 541 echo "enabled" 542 fi 543 ;; 544 545 *) 546 echo "ERROR: Unknown command '$1" >&2 547 return 1 548 ;; 549 esac 550} 551 552[ x"$1" != x"" ] || exit_failure_syntax 553 554action= 555window_id= 556 557case $1 in 558 suspend) 559 action="$1" 560 561 shift 562 563 if [ -z "$1" ] ; then 564 exit_failure_syntax "WindowID argument missing" 565 fi 566 567 window_id="$1" 568 check_window_id 569 ;; 570 571 resume) 572 action="$1" 573 574 shift 575 576 if [ -z "$1" ] ; then 577 exit_failure_syntax "WindowID argument missing" 578 fi 579 580 window_id="$1" 581 check_window_id 582 ;; 583 584 activate) 585 action="$1" 586 ;; 587 588 lock) 589 action="$1" 590 ;; 591 592 reset) 593 action="$1" 594 ;; 595 596 status) 597 action="$1" 598 ;; 599 600 *) 601 exit_failure_syntax "unknown command '$1'" 602 ;; 603esac 604 605detectDE 606# Consider "xscreensaver" a separate DE 607xscreensaver-command -version 2> /dev/null | grep XScreenSaver > /dev/null && DE="xscreensaver" 608# Consider "gnome-screensaver" a separate DE 609gnome-screensaver-command -q > /dev/null 2>&1 && DE="gnome_screensaver" 610 611if [ "$action" = "resume" ] ; then 612 do_resume 613 exit_success 614fi 615 616perform_action "$action" 617 618if [ "$action" = "suspend" ] ; then 619 # Start tracking $window_id and resume the screensaver once it disappears 620 ( track_window ) 2> /dev/null > /dev/null & 621fi 622 623if [ $result -eq 0 ]; then 624 exit_success 625else 626 exit_failure_operation_failed 627fi 628