From 7c2e6aa9152ffa4768cc8c0f062e3109443c7c15 Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Fri, 9 Sep 2022 22:52:30 -0400 Subject: [PATCH] From https://www.jwz.org/xscreensaver/xscreensaver-6.05.tar.gz -rw-rw-r-- 1 zblaxell zblaxell 26109536 Sep 9 21:41 xscreensaver-6.05.tar.gz 719e518de9a1223fd4071f5c49b09c0a6b23550b xscreensaver-6.05.tar.gz --- Makefile.in | 17 + OSX/Randomizer.m | 245 +- OSX/XScreenSaverView.m | 2 +- OSX/bindist.rtf | 2 +- OSX/grabclient-osx.m | 130 +- README | 41 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- config.h.in | 12 +- configure | 248 +- configure.ac | 165 +- driver/.gdbinit | 27 - driver/Makefile.in | 122 +- driver/XScreenSaver_ad.h | 7 +- driver/blurb.c | 27 +- driver/clientmsg.c | 3 +- driver/demo-Gtk-conf.c | 273 +- driver/demo-Gtk-conf.h | 49 +- driver/demo-Gtk.c | 4677 +++++++++-------- driver/demo.ui | 2680 ++++++++++ driver/dpms.c | 8 +- driver/fade.c | 10 +- driver/gresource.xml | 7 + driver/passwd-pwent.c | 7 +- driver/prefs.ui | 518 ++ driver/prefsw.c | 104 +- driver/subprocs.c | 12 +- driver/types.h | 3 + driver/windows.c | 8 +- driver/xscreensaver-auth.c | 74 +- driver/xscreensaver-auth.man | 2 +- driver/xscreensaver-command.man | 18 +- driver/xscreensaver-gfx.man | 2 +- driver/xscreensaver-settings.man | 22 +- driver/xscreensaver-systemd.c | 13 + driver/xscreensaver-systemd.man | 4 +- driver/xscreensaver.c | 3 +- driver/xscreensaver.man | 44 +- driver/xscreensaver.ui | 3060 ----------- hacks/abstractile.man | 37 +- hacks/anemone.man | 45 +- hacks/anemotaxis.man | 41 +- hacks/ant.man | 79 +- hacks/apollonian.man | 45 +- hacks/apple2.man | 71 +- hacks/attraction.man | 87 +- hacks/barcode.man | 39 +- hacks/binaryhorizon.man | 71 +- hacks/binaryring.man | 59 +- hacks/blaster.man | 41 +- hacks/blitspin.man | 38 +- hacks/bouboule.man | 30 +- hacks/boxfit.man | 61 +- hacks/braid.man | 30 +- hacks/bsod.c | 396 +- hacks/bsod.man | 35 +- hacks/bubbles.man | 54 +- hacks/bumps.man | 45 +- hacks/ccurve.man | 37 +- hacks/celtic.man | 41 +- hacks/cloudlife.man | 36 +- hacks/compass.man | 33 +- hacks/config/abstractile.xml | 23 +- hacks/config/anemone.xml | 28 +- hacks/config/anemotaxis.xml | 12 +- hacks/config/ant.xml | 30 +- hacks/config/antinspect.xml | 8 +- hacks/config/antmaze.xml | 6 +- hacks/config/antspotlight.xml | 6 +- hacks/config/apollonian.xml | 16 +- hacks/config/apple2.xml | 20 +- hacks/config/atlantis.xml | 18 +- hacks/config/attraction.xml | 43 +- hacks/config/atunnel.xml | 12 +- hacks/config/barcode.xml | 12 +- hacks/config/beats.xml | 22 +- hacks/config/binaryhorizon.xml | 16 +- hacks/config/binaryring.xml | 10 +- hacks/config/blaster.xml | 41 +- hacks/config/blinkbox.xml | 16 +- hacks/config/blitspin.xml | 11 +- hacks/config/blocktube.xml | 14 +- hacks/config/boing.xml | 20 +- hacks/config/bouboule.xml | 12 +- hacks/config/bouncingcow.xml | 14 +- hacks/config/boxed.xml | 20 +- hacks/config/boxfit.xml | 22 +- hacks/config/braid.xml | 14 +- hacks/config/bsod.xml | 99 +- hacks/config/bubble3d.xml | 16 +- hacks/config/bubbles.xml | 16 +- hacks/config/bumps.xml | 15 +- hacks/config/cage.xml | 8 +- hacks/config/carousel.xml | 22 +- hacks/config/ccurve.xml | 10 +- hacks/config/celtic.xml | 10 +- hacks/config/chompytower.xml | 20 +- hacks/config/circuit.xml | 14 +- hacks/config/cityflow.xml | 18 +- hacks/config/cloudlife.xml | 12 +- hacks/config/co____9.xml | 16 +- hacks/config/companioncube.xml | 16 +- hacks/config/compass.xml | 6 +- hacks/config/coral.xml | 12 +- hacks/config/covid19.xml | 16 +- hacks/config/crackberg.xml | 32 +- hacks/config/critical.xml | 8 +- hacks/config/crumbler.xml | 18 +- hacks/config/crystal.xml | 23 +- hacks/config/cube21.xml | 36 +- hacks/config/cubenetic.xml | 34 +- hacks/config/cubestack.xml | 16 +- hacks/config/cubestorm.xml | 20 +- hacks/config/cubetwist.xml | 20 +- hacks/config/cubicgrid.xml | 16 +- hacks/config/cwaves.xml | 10 +- hacks/config/cynosure.xml | 10 +- hacks/config/dangerball.xml | 16 +- hacks/config/decayscreen.xml | 36 +- hacks/config/deco.xml | 20 +- hacks/config/deepstars.xml | 10 +- hacks/config/deluxe.xml | 16 +- hacks/config/demon.xml | 14 +- hacks/config/discoball.xml | 16 +- hacks/config/discrete.xml | 10 +- hacks/config/distort.xml | 27 +- hacks/config/dnalogo.xml | 13 +- hacks/config/drift.xml | 10 +- hacks/config/dymaxionmap.xml | 24 +- hacks/config/endgame.xml | 8 +- hacks/config/energystream.xml | 10 +- hacks/config/engine.xml | 32 +- hacks/config/epicycle.xml | 26 +- hacks/config/eruption.xml | 18 +- hacks/config/esper.xml | 10 +- hacks/config/etruscanvenus.xml | 54 +- hacks/config/euler2d.xml | 20 +- hacks/config/extrusion.xml | 28 +- hacks/config/fadeplot.xml | 12 +- hacks/config/fiberlamp.xml | 10 +- hacks/config/filmleader.xml | 14 +- hacks/config/fireworkx.xml | 12 +- hacks/config/flag.xml | 14 +- hacks/config/flame.xml | 14 +- hacks/config/flipflop.xml | 18 +- hacks/config/flipscreen3d.xml | 8 +- hacks/config/fliptext.xml | 20 +- hacks/config/flow.xml | 24 +- hacks/config/fluidballs.xml | 20 +- hacks/config/flurry.xml | 18 +- hacks/config/flyingtoasters.xml | 18 +- hacks/config/fontglide.xml | 18 +- hacks/config/forest.xml | 8 +- hacks/config/fuzzyflakes.xml | 32 +- hacks/config/galaxy.xml | 14 +- hacks/config/gears.xml | 16 +- hacks/config/geodesic.xml | 24 +- hacks/config/geodesicgears.xml | 18 +- hacks/config/gflux.xml | 31 +- hacks/config/gibson.xml | 22 +- hacks/config/glblur.xml | 24 +- hacks/config/glcells.xml | 34 +- hacks/config/gleidescope.xml | 16 +- hacks/config/glforestfire.xml | 20 +- hacks/config/glhanoi.xml | 20 +- hacks/config/glitchpeg.xml | 8 +- hacks/config/glknots.xml | 30 +- hacks/config/glmatrix.xml | 26 +- hacks/config/glplanet.xml | 30 +- hacks/config/glschool.xml | 24 +- hacks/config/glslideshow.xml | 18 +- hacks/config/glsnake.xml | 20 +- hacks/config/gltext.xml | 28 +- hacks/config/goop.xml | 20 +- hacks/config/grav.xml | 14 +- hacks/config/gravitywell.xml | 12 +- hacks/config/greynetic.xml | 8 +- hacks/config/halftone.xml | 20 +- hacks/config/halo.xml | 16 +- hacks/config/handsy.xml | 30 +- hacks/config/headroom.xml | 28 +- hacks/config/helix.xml | 8 +- hacks/config/hexadrop.xml | 26 +- hacks/config/hexstrut.xml | 18 +- hacks/config/hilbert.xml | 26 +- hacks/config/hopalong.xml | 34 +- hacks/config/hydrostat.xml | 28 +- hacks/config/hyperball.xml | 20 +- hacks/config/hypercube.xml | 29 +- hacks/config/hypertorus.xml | 44 +- hacks/config/hypnowheel.xml | 18 +- hacks/config/ifs.xml | 18 +- hacks/config/imsmap.xml | 18 +- hacks/config/interaggregate.xml | 8 +- hacks/config/interference.xml | 20 +- hacks/config/intermomentary.xml | 8 +- hacks/config/jigglypuff.xml | 32 +- hacks/config/jigsaw.xml | 17 +- hacks/config/juggle.xml | 28 +- hacks/config/juggler3d.xml | 27 +- hacks/config/julia.xml | 12 +- hacks/config/kaleidescope.xml | 16 +- hacks/config/kaleidocycle.xml | 28 +- hacks/config/klein.xml | 64 +- hacks/config/kumppa.xml | 13 +- hacks/config/lament.xml | 10 +- hacks/config/laser.xml | 12 +- hacks/config/lavalite.xml | 42 +- hacks/config/lcdscrub.xml | 28 +- hacks/config/lightning.xml | 8 +- hacks/config/lisa.xml | 14 +- hacks/config/lissie.xml | 14 +- hacks/config/lmorph.xml | 16 +- hacks/config/lockward.xml | 20 +- hacks/config/loop.xml | 12 +- hacks/config/m6502.xml | 18 +- hacks/config/mapscroller.xml | 110 +- hacks/config/marbling.xml | 12 +- hacks/config/maze.xml | 20 +- hacks/config/maze3d.xml | 98 +- hacks/config/memscroller.xml | 10 +- hacks/config/menger.xml | 30 +- hacks/config/metaballs.xml | 18 +- hacks/config/mirrorblob.xml | 30 +- hacks/config/mismunch.xml | 12 +- hacks/config/moebius.xml | 10 +- hacks/config/moebiusgears.xml | 20 +- hacks/config/moire.xml | 14 +- hacks/config/moire2.xml | 10 +- hacks/config/molecule.xml | 40 +- hacks/config/morph3d.xml | 16 +- hacks/config/mountain.xml | 10 +- hacks/config/munch.xml | 16 +- hacks/config/nakagin.xml | 16 +- hacks/config/nerverot.xml | 26 +- hacks/config/noof.xml | 6 +- hacks/config/noseguy.xml | 4 +- hacks/config/pacman.xml | 8 +- hacks/config/pedal.xml | 12 +- hacks/config/peepers.xml | 20 +- hacks/config/penetrate.xml | 10 +- hacks/config/penrose.xml | 12 +- hacks/config/petri.xml | 32 +- hacks/config/phosphor.xml | 14 +- hacks/config/photopile.xml | 24 +- hacks/config/piecewise.xml | 14 +- hacks/config/pinion.xml | 16 +- hacks/config/pipes.xml | 24 +- hacks/config/polyhedra.xml | 322 +- hacks/config/polyominoes.xml | 12 +- hacks/config/polytopes.xml | 40 +- hacks/config/pong.xml | 14 +- hacks/config/popsquares.xml | 34 +- hacks/config/projectiveplane.xml | 62 +- hacks/config/providence.xml | 10 +- hacks/config/pulsar.xml | 24 +- hacks/config/pyro.xml | 12 +- hacks/config/qix.xml | 30 +- hacks/config/quasicrystal.xml | 18 +- hacks/config/queens.xml | 8 +- hacks/config/raverhoop.xml | 20 +- hacks/config/razzledazzle.xml | 18 +- hacks/config/rdbomb.xml | 24 +- hacks/config/ripples.xml | 20 +- hacks/config/rocks.xml | 22 +- hacks/config/romanboy.xml | 56 +- hacks/config/rorschach.xml | 14 +- hacks/config/rotor.xml | 14 +- hacks/config/rotzoomer.xml | 22 +- hacks/config/rubik.xml | 14 +- hacks/config/rubikblocks.xml | 26 +- hacks/config/sballs.xml | 26 +- hacks/config/scooter.xml | 14 +- hacks/config/shadebobs.xml | 15 +- hacks/config/sierpinski.xml | 12 +- hacks/config/sierpinski3d.xml | 12 +- hacks/config/skytentacles.xml | 30 +- hacks/config/slidescreen.xml | 16 +- hacks/config/slip.xml | 12 +- hacks/config/sonar.xml | 45 +- hacks/config/speedmine.xml | 37 +- hacks/config/sphere.xml | 8 +- hacks/config/sphereeversion.xml | 58 +- hacks/config/spheremonics.xml | 34 +- hacks/config/spiral.xml | 12 +- hacks/config/splitflap.xml | 36 +- hacks/config/splodesic.xml | 14 +- hacks/config/spotlight.xml | 10 +- hacks/config/sproingies.xml | 12 +- hacks/config/squiral.xml | 18 +- hacks/config/squirtorus.xml | 12 +- hacks/config/stairs.xml | 6 +- hacks/config/starfish.xml | 16 +- hacks/config/starwars.xml | 30 +- hacks/config/stonerview.xml | 10 +- hacks/config/strange.xml | 20 +- hacks/config/substrate.xml | 18 +- hacks/config/superquadrics.xml | 14 +- hacks/config/surfaces.xml | 42 +- hacks/config/swirl.xml | 12 +- hacks/config/t3d.xml | 22 +- hacks/config/tangram.xml | 20 +- hacks/config/tessellimage.xml | 20 +- hacks/config/testx11.xml | 4 +- hacks/config/thornbird.xml | 16 +- hacks/config/timetunnel.xml | 22 +- hacks/config/topblock.xml | 32 +- hacks/config/triangle.xml | 8 +- hacks/config/tronbit.xml | 14 +- hacks/config/truchet.xml | 22 +- hacks/config/twang.xml | 20 +- hacks/config/unicrud.xml | 24 +- hacks/config/unknownpleasures.xml | 27 +- hacks/config/vermiculate.xml | 6 +- hacks/config/vfeedback.xml | 14 +- hacks/config/vidwhacker.xml | 8 +- hacks/config/vigilance.xml | 8 +- hacks/config/vines.xml | 8 +- hacks/config/voronoi.xml | 21 +- hacks/config/wander.xml | 18 +- hacks/config/webcollage.xml | 17 +- hacks/config/whirlwindwarp.xml | 8 +- hacks/config/whirlygig.xml | 76 +- hacks/config/winduprobot.xml | 20 +- hacks/config/worm.xml | 15 +- hacks/config/wormhole.xml | 10 +- hacks/config/xanalogtv.xml | 14 +- hacks/config/xflame.xml | 18 +- hacks/config/xjack.xml | 8 +- hacks/config/xlyap.xml | 31 +- hacks/config/xmatrix.xml | 28 +- hacks/config/xrayswarm.xml | 6 +- hacks/config/xspirograph.xml | 10 +- hacks/config/zoom.xml | 22 +- hacks/coral.man | 41 +- hacks/critical.man | 34 +- hacks/crystal.man | 57 +- hacks/cwaves.man | 49 +- hacks/cynosure.man | 37 +- hacks/decayscreen.man | 45 +- hacks/deco.man | 75 +- hacks/deluxe.man | 49 +- hacks/demon.man | 45 +- hacks/discrete.man | 37 +- hacks/distort.man | 87 +- hacks/drift.man | 36 +- hacks/epicycle.man | 77 +- hacks/eruption.man | 47 +- hacks/euler2d.man | 45 +- hacks/fadeplot.man | 41 +- hacks/fiberlamp.man | 41 +- hacks/filmleader.man | 45 +- hacks/fireworkx.man | 45 +- hacks/flag.man | 44 +- hacks/flame.man | 34 +- hacks/flow.man | 79 +- hacks/fluidballs.c | 6 +- hacks/fluidballs.man | 59 +- hacks/fontglide.man | 75 +- hacks/forest.man | 26 +- hacks/fuzzyflakes.man | 67 +- hacks/galaxy.man | 40 +- hacks/glitchpeg.man | 33 +- hacks/glx/antinspect.man | 23 +- hacks/glx/antmaze.man | 21 +- hacks/glx/antspotlight.man | 23 +- hacks/glx/atlantis.man | 53 +- hacks/glx/atunnel.man | 35 +- hacks/glx/beats.man | 45 +- hacks/glx/blinkbox.man | 49 +- hacks/glx/blocktube.man | 49 +- hacks/glx/boing.man | 67 +- hacks/glx/bouncingcow.man | 49 +- hacks/glx/boxed.man | 33 +- hacks/glx/bubble3d.man | 37 +- hacks/glx/cage.man | 37 +- hacks/glx/carousel.man | 63 +- hacks/glx/chompytower.man | 57 +- hacks/glx/circuit.man | 49 +- hacks/glx/cityflow.man | 53 +- hacks/glx/companioncube.man | 53 +- hacks/glx/covid19.man | 49 +- hacks/glx/crackberg.man | 75 +- hacks/glx/crumbler.man | 53 +- hacks/glx/cube21.man | 89 +- hacks/glx/cubenetic.man | 65 +- hacks/glx/cubestack.man | 49 +- hacks/glx/cubestorm.man | 53 +- hacks/glx/cubetwist.man | 57 +- hacks/glx/cubicgrid.man | 57 +- hacks/glx/dangerball.man | 49 +- hacks/glx/deepstars.man | 33 +- hacks/glx/discoball.man | 49 +- hacks/glx/dymaxionmap.man | 73 +- hacks/glx/endgame.man | 41 +- hacks/glx/energystream.man | 33 +- hacks/glx/engine.man | 45 +- hacks/glx/esper.man | 37 +- hacks/glx/etruscanvenus.man | 181 +- hacks/glx/extrusion.man | 43 +- hacks/glx/flipflop.man | 64 +- hacks/glx/flipscreen3d.man | 37 +- hacks/glx/fliptext.man | 61 +- hacks/glx/flurry.man | 29 +- hacks/glx/flyingtoasters.man | 53 +- hacks/glx/gears.man | 41 +- hacks/glx/geodesic.man | 49 +- hacks/glx/geodesicgears.man | 53 +- hacks/glx/gflux.man | 61 +- hacks/glx/gibson.man | 61 +- hacks/glx/glblur.man | 45 +- hacks/glx/glcells.man | 59 +- hacks/glx/gleidescope.man | 37 +- hacks/glx/glforestfire.man | 71 +- hacks/glx/glhanoi.man | 59 +- hacks/glx/glknots.man | 57 +- hacks/glx/glmatrix.man | 75 +- hacks/glx/glplanet.man | 53 +- hacks/glx/glschool.man | 93 +- hacks/glx/glslideshow.man | 81 +- hacks/glx/glsnake.man | 43 +- hacks/glx/gltext.man | 71 +- hacks/glx/gravitywell.man | 41 +- hacks/glx/handsy.man | 53 +- hacks/glx/headroom.man | 51 +- hacks/glx/hexstrut.man | 53 +- hacks/glx/hilbert.man | 67 +- hacks/glx/hydrostat.man | 73 +- hacks/glx/hypertorus.man | 115 +- hacks/glx/hypnowheel.man | 53 +- hacks/glx/jigglypuff.man | 27 +- hacks/glx/jigsaw.man | 48 +- hacks/glx/juggler3d.man | 105 +- hacks/glx/kaleidocycle.man | 51 +- hacks/glx/klein.man | 175 +- hacks/glx/lament.man | 31 +- hacks/glx/lavalite.man | 85 +- hacks/glx/lockward.man | 61 +- hacks/glx/mapscroller.man | 57 +- hacks/glx/maze3d.man | 81 +- hacks/glx/menger.man | 53 +- hacks/glx/mirrorblob.man | 81 +- hacks/glx/moebius.man | 31 +- hacks/glx/moebiusgears.man | 47 +- hacks/glx/molecule.c | 4 +- hacks/glx/molecule.man | 93 +- hacks/glx/morph3d.man | 33 +- hacks/glx/nakagin.man | 49 +- hacks/glx/noof.man | 29 +- hacks/glx/peepers.man | 55 +- hacks/glx/photopile.man | 71 +- hacks/glx/pinion.man | 47 +- hacks/glx/pipes.man | 41 +- hacks/glx/polyhedra.man | 59 +- hacks/glx/polytopes.man | 93 +- hacks/glx/projectiveplane.man | 173 +- hacks/glx/providence.man | 37 +- hacks/glx/pulsar.man | 77 +- hacks/glx/quasicrystal.man | 53 +- hacks/glx/queens.man | 35 +- hacks/glx/raverhoop.man | 57 +- hacks/glx/razzledazzle.man | 49 +- hacks/glx/romanboy.man | 173 +- hacks/glx/rubik.man | 45 +- hacks/glx/rubikblocks.man | 85 +- hacks/glx/sballs.man | 51 +- hacks/glx/sierpinski3d.man | 41 +- hacks/glx/skytentacles.man | 77 +- hacks/glx/sonar.man | 109 +- hacks/glx/sphereeversion.man | 165 +- hacks/glx/spheremonics.man | 65 +- hacks/glx/splitflap.man | 69 +- hacks/glx/splodesic.man | 45 +- hacks/glx/sproingies.man | 45 +- hacks/glx/squirtorus.man | 37 +- hacks/glx/stairs.man | 33 +- hacks/glx/starwars.man | 85 +- hacks/glx/stonerview.man | 29 +- hacks/glx/superquadrics.man | 45 +- hacks/glx/surfaces.man | 113 +- hacks/glx/tangram.man | 41 +- hacks/glx/timetunnel.man | 81 +- hacks/glx/topblock.man | 97 +- hacks/glx/trackball.h | 2 +- hacks/glx/tronbit.man | 45 +- hacks/glx/unicrud.man | 51 +- hacks/glx/unknownpleasures.man | 65 +- hacks/glx/vigilance.man | 33 +- hacks/glx/voronoi.man | 49 +- hacks/glx/winduprobot.man | 57 +- hacks/glx/xscreensaver-gl-visual.man | 2 +- hacks/goop.man | 48 +- hacks/grav.man | 36 +- hacks/greynetic.man | 26 +- hacks/halftone.man | 57 +- hacks/halo.man | 34 +- hacks/helix.man | 28 +- hacks/hexadrop.man | 53 +- hacks/hopalong.man | 38 +- hacks/hyperball.man | 65 +- hacks/hypercube.man | 59 +- hacks/ifs.man | 73 +- hacks/imsmap.man | 34 +- hacks/interaggregate.man | 47 +- hacks/interference.man | 61 +- hacks/intermomentary.man | 52 +- hacks/juggle.man | 110 +- hacks/julia.man | 30 +- hacks/kaleidescope.man | 34 +- hacks/kumppa.man | 41 +- hacks/laser.man | 30 +- hacks/lcdscrub.man | 37 +- hacks/lightning.man | 26 +- hacks/lisa.man | 32 +- hacks/lissie.man | 45 +- hacks/lmorph.man | 34 +- hacks/loop.man | 41 +- hacks/marbling.man | 37 +- hacks/maze.man | 42 +- hacks/memscroller.man | 43 +- hacks/metaballs.man | 49 +- hacks/moire.man | 32 +- hacks/moire2.man | 37 +- hacks/mountain.man | 37 +- hacks/munch.man | 47 +- hacks/munge-ad.pl | 6 +- hacks/nerverot.man | 54 +- hacks/noseguy.man | 55 +- hacks/pacman.man | 43 +- hacks/pedal.man | 28 +- hacks/penetrate.man | 55 +- hacks/penrose.man | 34 +- hacks/petri.man | 54 +- hacks/phosphor.man | 53 +- hacks/piecewise.man | 53 +- hacks/polyominoes.man | 41 +- hacks/pong.man | 37 +- hacks/pyro.man | 30 +- hacks/qix.man | 80 +- hacks/rdbomb.man | 45 +- hacks/recanim.c | 15 +- hacks/ripples.man | 69 +- hacks/rocks.man | 38 +- hacks/rorschach.man | 36 +- hacks/rotor.man | 45 +- hacks/rotzoomer.man | 45 +- hacks/scooter.man | 51 +- hacks/screenhack.c | 44 +- hacks/shadebobs.man | 41 +- hacks/sierpinski.man | 30 +- hacks/slidescreen.man | 57 +- hacks/slip.man | 39 +- hacks/speedmine.man | 92 +- hacks/sphere.man | 26 +- hacks/spiral.man | 30 +- hacks/spotlight.man | 39 +- hacks/squiral.man | 37 +- hacks/starfish.man | 40 +- hacks/strange.man | 36 +- hacks/substrate.man | 58 +- hacks/swirl.man | 37 +- hacks/t3d.man | 2 +- hacks/tessellimage.man | 53 +- hacks/thornbird.man | 41 +- hacks/triangle.man | 33 +- hacks/truchet.man | 77 +- hacks/twang.man | 81 +- hacks/vermiculate.man | 25 +- hacks/vfeedback.man | 47 +- hacks/vidwhacker.man | 27 +- hacks/vines.man | 26 +- hacks/wander.man | 53 +- hacks/webcollage.man | 85 +- hacks/whirlwindwarp.man | 28 +- hacks/whirlygig.man | 67 +- hacks/worm.man | 41 +- hacks/wormhole.man | 43 +- hacks/xanalogtv.man | 25 +- hacks/xflame.man | 37 +- hacks/ximage-loader.c | 9 +- hacks/xjack.man | 14 +- hacks/xlyap.man | 103 +- hacks/xmatrix.man | 73 +- hacks/xml2man.pl | 27 +- hacks/xrayswarm.man | 27 +- hacks/xscreensaver-getimage-file | 9 +- hacks/xscreensaver-getimage.c | 76 +- hacks/xscreensaver-getimage.man | 4 +- hacks/xscreensaver-text | 17 +- hacks/xscreensaver-text.man | 2 +- hacks/xspirograph.man | 37 +- hacks/xsublim.man | 54 +- hacks/zoom.man | 55 +- utils/async_netdb.c | 7 +- utils/images/screensaver-cmndln.png | Bin 1040 -> 0 bytes utils/images/screensaver-colorselector.png | Bin 1104 -> 0 bytes utils/images/screensaver-diagnostic.png | Bin 1307 -> 0 bytes utils/images/screensaver-locking.png | Bin 944 -> 0 bytes utils/images/screensaver-power.png | Bin 973 -> 0 bytes utils/images/screensaver-snap.png | Bin 1272 -> 0 bytes utils/resources.c | 1 + utils/version.h | 6 +- 601 files changed, 17841 insertions(+), 15349 deletions(-) delete mode 100644 driver/.gdbinit create mode 100644 driver/demo.ui create mode 100644 driver/gresource.xml create mode 100644 driver/prefs.ui delete mode 100644 driver/xscreensaver.ui delete mode 100644 utils/images/screensaver-cmndln.png delete mode 100644 utils/images/screensaver-colorselector.png delete mode 100644 utils/images/screensaver-diagnostic.png delete mode 100644 utils/images/screensaver-locking.png delete mode 100644 utils/images/screensaver-power.png delete mode 100644 utils/images/screensaver-snap.png diff --git a/Makefile.in b/Makefile.in index 9de79b20..fa033cf9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -286,6 +286,22 @@ dmg:: apk:: $(MAKE2) -C android apk +# Update the version numbers in faq.html, bugs.html, etc. +www_versions:: + @ \ + DEST=$$HOME/www/xscreensaver ; \ + VERS=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ]*\).*/\1/p' utils/version.h | \ + head -1` ; \ + TMP=/tmp/xd.$$$$ ; \ + for f in $$DEST/*.html ; do \ + sed "s/\(CLASS=.latest.>\)[^<>]*\(<\)/\1$$VERS\2/gi" < "$$f" > "$$TMP" ;\ + if ! cmp -s "$$f" "$$TMP" ; then \ + diff -U0 "$$f" "$$TMP" ; \ + cp -p "$$TMP" "$$f" ; \ + fi ; \ + rm -f "$$TMP" ; \ + done + www:: @ \ DEST=$$HOME/www/xscreensaver ; \ @@ -308,6 +324,7 @@ www:: exit 1 ; \ fi ; \ \ + $(MAKE2) www_versions ; \ $(MAKE2) -C OSX updates.xml ; \ \ if [ ! -f $$NAME ]; then \ diff --git a/OSX/Randomizer.m b/OSX/Randomizer.m index be302f89..e055f737 100644 --- a/OSX/Randomizer.m +++ b/OSX/Randomizer.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright © 2020-2021 Jamie Zawinski +/* xscreensaver, Copyright © 2020-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -28,69 +28,123 @@ #define CYCLE_DEFAULT (5 * 60) -// Returns a string that (hopefully) uniquely identifies the NSScreen, -// and will survive reboots. Also the pretty name of that screen. +// Returns a string that (hopefully) uniquely identifies the display hardware +// associated with this NSScreen in such a way that it will persist across +// reboots. Also the pretty name of that screen. // static NSArray * screen_id (NSScreen *screen) { + NSData *edid = NULL; + NSString *name = NULL; + NSDictionary *d = [screen deviceDescription]; - // This is the CGDirectDisplayID. "A display ID can persist across - // processes and typically remains constant until the machine is - // restarted." It does not always persist across reboots. + // This is the CGDirectDisplayID. "A display ID can persist across processes + // and typically remains constant until the machine is restarted." It does + // not always persist across reboots. // unsigned long id = [[d objectForKey:@"NSScreenNumber"] unsignedLongValue]; - // The EDID of a display contains manufacturer, product ID, and most - // importantly, serial number. So that should persist. + // Aug 2022: CGDisplayIOServicePort has been deprecated since 10.9, and as + // of 12.5, it always returns NULL, at least on M1 hardware. Perhaps this + // should be #if __x86_64__ or !__arm64__? // # pragma clang diagnostic push // "CGDisplayIOServicePort deprecated in 10.9" # pragma clang diagnostic ignored "-Wdeprecated-declarations" - io_service_t display_port = CGDisplayIOServicePort(id); + io_service_t dport = CGDisplayIOServicePort (id); # pragma clang diagnostic pop - if (display_port == MACH_PORT_NULL) { - // No physical device to get a name from... are we in Screen Sharing? - NSLog(@"no device for display %lu", id); - return @[ [NSString stringWithFormat:@"%08lX", id], - @"unknown" ]; + if (dport != MACH_PORT_NULL) { + NSDictionary *d2 = (NSDictionary *) // CFDictionaryRef + IODisplayCreateInfoDictionary (dport, kIODisplayOnlyPreferredName); + + // This returns the EDID as a 256-bytes binary blob that contains, among + // other things, the manufacturer, product ID, and unique serial number. + // + edid = [d2 objectForKey:[NSString stringWithUTF8String:kIODisplayEDIDKey]]; + + // Now get the human-readable name of the screen. + // The dict has an entry like: "DisplayProductName": { "en_US": "iMac" }; + // + NSDictionary *names = + [d2 objectForKey: [NSString stringWithUTF8String:kDisplayProductName]]; + if (names && [names count] > 0) + name = [[names objectForKey:[[names allKeys] objectAtIndex:0]] retain]; + + [d2 release]; } - NSDictionary *d2 = (NSDictionary *) // CFDictionaryRef - IODisplayCreateInfoDictionary (display_port, kIODisplayOnlyPreferredName); - NSData *edid = [d2 objectForKey: - [NSString stringWithUTF8String:kIODisplayEDIDKey]]; - NSString *b64; - if (!edid) { - // For ancient monitors and safe-mode graphics drivers. - b64 = [NSString stringWithFormat:@"%08lX", id]; - } else { - // But the EDID is 256 binary bytes. That's annoyingly big. - // So let's hash and base64 it for use as the resource key. - // That's 43 characters. + if (! edid) { + // + // If we weren't able to retrieve the full 256-byte EDID above, hopefully + // these three numbers also uniquely identify the hardware. + // + // However, they won't always. I have an "EDID Ghost" adapter (a dongle + // to prevent resolution negotiation) whose serial number is 0. Maybe if + // I had two of them, even the 256-byte version would be non-unique. + // + // We could also dig through IOServiceMatching("IOMobileFramebuffer") in + // order to find more info about the displays in the "DisplayAttributes" + // dictionary (see "ioreg -lw0") but that probably won't give us anything + // more unique than the above. In particular, that dict contains an + // entry for "EDID UUID" which is a hex string of 16 bytes that does + // *not* distinguish between two different monitors of the same model. // + uint32_t bin[3]; + bin[0] = CGDisplayVendorNumber (id); + bin[1] = CGDisplayModelNumber (id); + bin[2] = CGDisplaySerialNumber (id); + if (bin[0] || bin[1] || bin[2]) + edid = [NSData dataWithBytes:bin length:sizeof(bin)]; + } + + if (!name || !name.length) { + // + // We might have gotten the name from CGDisplayIOServicePort -> + // kIODisplayOnlyPreferredName. If not, use the localized display name. + // which was introduced in macOS 10.15. Maybe those are identical? + // + if (@available (macOS 10.15, *)) + name = [screen localizedName]; + if (!name || !name.length) + name = @"unknown"; + } + + if (! edid) { + // + // If we weren't able to find the EDID at all, use the display name, size + // and position, and hope that is invariant across boots. Good luck! + // + edid = [[NSString stringWithFormat:@"%dx%d @ %d+%d, %@", + (int) screen.frame.size.width, + (int) screen.frame.size.height, + (int) screen.frame.origin.x, + (int) screen.frame.origin.y, + name] + dataUsingEncoding: NSUTF8StringEncoding]; + } + + // + // The EDID might be only 12 bytes, or it might be 256 bytes, which is + // annoyingly big. Or somewhere in between. So if it's more than 32 bytes, + // hash it first. After base64, the resource key will be no more than 43 + // characters. + // + if (edid.length > CC_SHA256_DIGEST_LENGTH) { const char *bytes = [edid bytes]; unsigned char out[CC_SHA256_DIGEST_LENGTH + 1]; CC_SHA256 (bytes, edid.length, out); - b64 = [[NSData dataWithBytes:bytes length:CC_SHA256_DIGEST_LENGTH] - base64EncodedStringWithOptions:0]; - // Replace irritating b64 characters with safer ones. - b64 = [[[b64 stringByReplacingOccurrencesOfString:@"+" withString:@"-"] - stringByReplacingOccurrencesOfString:@"/" withString:@"_"] - stringByReplacingOccurrencesOfString:@"=" withString:@""]; + edid = [NSData dataWithBytes: out + length: CC_SHA256_DIGEST_LENGTH]; } - // Now get the human-readable name of the screen. - // The dict has an entry like: "DisplayProductName": { "en_US": "iMac" }; - // - NSString *name = @"unknown"; - NSDictionary *names = - [d2 objectForKey: [NSString stringWithUTF8String:kDisplayProductName]]; - if (names && [names count] > 0) - name = [[names objectForKey:[[names allKeys] objectAtIndex:0]] retain]; + NSString *b64 = [edid base64EncodedStringWithOptions:0]; - [d2 release]; + // Replace irritating b64 characters with safer ones. + b64 = [[[b64 stringByReplacingOccurrencesOfString:@"+" withString:@"-"] + stringByReplacingOccurrencesOfString:@"/" withString:@"_"] + stringByReplacingOccurrencesOfString:@"=" withString:@""]; return @[ b64, name ]; // Analyzer says name leaks? } @@ -118,21 +172,11 @@ get_boolean (NSString *key, NSUserDefaultsController *prefs) static NSString * -resource_key_for_name (NSString *s, BOOL screen_p) +resource_key_for_name (NSString *s, BOOL screen_p, NSDictionary *screen_ids) { if (screen_p) { - const char *name = [s UTF8String]; - int n; - char dummy; - if (2 != sscanf (name, "Screen %d %c", &n, &dummy)) - return 0; - - NSArray *dscreens = [NSScreen screens]; - NSScreen *sc = [dscreens objectAtIndex: n-1]; - NSArray *aa = screen_id (sc); - NSString *id = [aa objectAtIndex:0]; + NSString *id = [screen_ids objectForKey: s]; return [NSString stringWithFormat:@"screen_%@_disabled", id]; - } else { // Keep risky characters out of the preferences database. NSMutableCharacterSet *set = @@ -184,8 +228,8 @@ resource_key_for_name (NSString *s, BOOL screen_p) if (p && frame.size.width >= 640) p = NO; - if (p && getenv("SELECTED_SAVER")) // Running under SaverTester - p = NO; +// if (p && getenv("SELECTED_SAVER")) // Running under SaverTester +// p = NO; self = [super initWithFrame:frame isPreview:p]; if (! self) return 0; @@ -313,7 +357,7 @@ resource_key_for_name (NSString *s, BOOL screen_p) [seen setObject:p forKey: [name lowercaseString]]; - NSString *res = resource_key_for_name (name, FALSE); + NSString *res = resource_key_for_name (name, FALSE, NULL); BOOL disabled = get_boolean (res, prefs); if (disabled) { // NSLog(@"disabled: %@", name); @@ -1000,7 +1044,9 @@ catch_signal (int sig, void (*handler) (int)) { NSTableView *screen_table, *saver_table; NSTextField *timerLabel; - NSArray *screens, *savers; + NSArray *savers; + NSArray *screen_names; // Readable, sortable strings printed in the list + NSDictionary *screen_ids; // screen_names -> resource id NSUserDefaultsController *prefs; } @@ -1017,8 +1063,8 @@ catch_signal (int sig, void (*handler) (int)) NSRect frame; frame.origin.x = 0; frame.origin.y = 0; - frame.size.width = 400; - frame.size.height = 480; + frame.size.width = 460; + frame.size.height = 520; [self setFrame:frame display:NO]; self.minSize = frame.size; frame.size.height = 99999; @@ -1177,23 +1223,57 @@ catch_signal (int sig, void (*handler) (int)) // Screen table view + NSArray *dscreens = [NSScreen screens]; + + NSMutableDictionary *screen_ords = + [NSMutableDictionary dictionaryWithCapacity: [dscreens count]]; + { - NSArray *dscreens = [NSScreen screens]; - NSMutableArray *s2 = [NSMutableArray arrayWithCapacity: [dscreens count]]; + // Save the original number of the screens. for (int i = 0; i < [dscreens count]; i++) { NSScreen *sc = [dscreens objectAtIndex: i]; + NSDictionary *d = [sc deviceDescription]; + NSNumber *sid = [d objectForKey:@"NSScreenNumber"]; + [screen_ords setObject: [NSNumber numberWithInteger:i] forKey: sid]; + } + + // Sort the screens left to right, then top to bottom. + dscreens = [dscreens sortedArrayUsingComparator: + ^ NSComparisonResult (id a, id b) { + NSScreen *sa = a; + NSScreen *sb = b; + return (sa.frame.origin.x > sb.frame.origin.x ? NSOrderedDescending : + sa.frame.origin.x < sb.frame.origin.x ? NSOrderedAscending : + sa.frame.origin.y > sb.frame.origin.y ? NSOrderedDescending : + sa.frame.origin.y < sb.frame.origin.y ? NSOrderedAscending : + NSOrderedSame); + }]; + + NSMutableArray *sn = [NSMutableArray arrayWithCapacity: [dscreens count]]; + NSMutableDictionary *si = [NSMutableDictionary + dictionaryWithCapacity:[dscreens count]]; + for (int i = 0; i < [dscreens count]; i++) { + NSScreen *sc = [dscreens objectAtIndex: i]; + NSDictionary *d = [sc deviceDescription]; + NSNumber *sid = [d objectForKey:@"NSScreenNumber"]; + int ord = [(NSNumber *) [screen_ords objectForKey: sid] integerValue]; + NSArray *aa = screen_id (sc); + NSString *id = [aa objectAtIndex:0]; NSString *desc = [aa objectAtIndex:1]; - [s2 addObject: [NSString stringWithFormat: - @"Screen %d - %d x %d @ %d, %d (%@)", - (i + 1), - (int) sc.frame.size.width, - (int) sc.frame.size.height, - (int) sc.frame.origin.x, - (int) sc.frame.origin.y, - desc]]; + NSString *name = [NSString stringWithFormat: + @"Screen %d - %d x %d @ %d, %d (%@)", + (ord + 1), + (int) sc.frame.size.width, + (int) sc.frame.size.height, + (int) sc.frame.origin.x, + (int) sc.frame.origin.y, + desc]; + [sn addObject: name]; + [si setObject:id forKey:name]; } - screens = [s2 retain]; + screen_names = [sn retain]; + screen_ids = [si retain]; } NSScrollView *sv = [[NSScrollView alloc] init]; @@ -1233,13 +1313,13 @@ catch_signal (int sig, void (*handler) (int)) frame.size.width = panel.frame.size.width - margin * 2; frame.size.height = stab.frame.size.height; frame.size.height += line_height * 2; // tab headers, sigh - int max = line_height * 5; + int max = line_height * 10; // 7 = 3 lines?? if (frame.size.height > max) frame.size.height = max; frame.origin.x = margin; frame.origin.y = hlab.frame.origin.y - frame.size.height - margin; sv.frame = frame; - if ([screens count] <= 1) { // Hide the screens list if there's only one. + if ([screen_names count] <= 1) { // Hide the screens list if only one. [sv removeFromSuperview]; frame.origin.y += frame.size.height + margin; frame.size.height = 0; @@ -1378,7 +1458,7 @@ catch_signal (int sig, void (*handler) (int)) - (NSInteger)numberOfRowsInTableView:(NSTableView *) tv { if (tv == screen_table) { - return [screens count]; + return [screen_names count]; } else if (tv == saver_table) { return [savers count]; } else { @@ -1416,9 +1496,9 @@ catch_signal (int sig, void (*handler) (int)) { BOOL screen_p = (tv == screen_table); NSString *s = (screen_p - ? [screens objectAtIndex: y] + ? [screen_names objectAtIndex: y] : [savers objectAtIndex: y]); - return resource_key_for_name (s, screen_p); + return resource_key_for_name (s, screen_p, screen_ids); } @@ -1432,7 +1512,7 @@ catch_signal (int sig, void (*handler) (int)) NSString *s; if (tv == screen_table) { - s = [screens objectAtIndex: y]; + s = [screen_names objectAtIndex: y]; } else { // if (tv == saver_table) { s = [savers objectAtIndex: y]; } @@ -1474,7 +1554,7 @@ catch_signal (int sig, void (*handler) (int)) sortDescriptorsDidChange: (NSArray *) od { BOOL screen_p = (tv == screen_table); - NSArray *aa = (screen_p ? screens : savers); + NSArray *aa = (screen_p ? screen_names : savers); // Only one column should be sorting at a time. Surely this is the wrong // right way to accomplish this, as I don't know which of the two columns @@ -1499,7 +1579,7 @@ catch_signal (int sig, void (*handler) (int)) NSMutableDictionary *cc = [[NSMutableDictionary alloc] init]; for (NSString *s in aa) { - NSString *res = resource_key_for_name (s, screen_p); + NSString *res = resource_key_for_name (s, screen_p, screen_ids); BOOL checked = !get_boolean (res, prefs); [cc setObject:[NSNumber numberWithBool: checked] forKey:s]; } @@ -1518,8 +1598,8 @@ catch_signal (int sig, void (*handler) (int)) [aa retain]; if (tv == screen_table) { - [screens release]; - screens = aa; + [screen_names release]; + screen_names = aa; } else if (tv == saver_table) { [savers release]; savers = aa; @@ -1532,7 +1612,7 @@ catch_signal (int sig, void (*handler) (int)) - (void) selectAllAction:(NSObject *)arg selected:(BOOL)selected { for (NSString *s in savers) { - NSString *res = resource_key_for_name (s, NO); + NSString *res = resource_key_for_name (s, NO, screen_ids); if (selected) // checkmark means no "disabled" entry in prefs [[prefs defaults] removeObjectForKey: res]; else @@ -1564,7 +1644,8 @@ catch_signal (int sig, void (*handler) (int)) - (void) dealloc { - [screens release]; + [screen_names release]; + [screen_ids release]; [savers release]; [super dealloc]; } diff --git a/OSX/XScreenSaverView.m b/OSX/XScreenSaverView.m index 3b395e88..92d46b4f 100644 --- a/OSX/XScreenSaverView.m +++ b/OSX/XScreenSaverView.m @@ -1642,7 +1642,7 @@ gl_check_ver (const struct gl_version *caps, jwxyz_window_resized (xdpy); # if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR - NSLog(@"reshape %.0fx%.0f", new_size.width, new_size.height); + NSLog(@"reshape %.0fx%.0f %.1fx", new_size.width, new_size.height, s); # endif // Next time render_x11 is called, run the saver's reshape_cb. diff --git a/OSX/bindist.rtf b/OSX/bindist.rtf index 28bf0dec..bbef05fc 100644 --- a/OSX/bindist.rtf +++ b/OSX/bindist.rtf @@ -23,7 +23,7 @@ version 6.04\ \pard\pardeftab720 \cf0 \ -\b To install all 240+ screen savers:\ +\b To install all 250+ screen savers:\ \pard\pardeftab720\li360 \b0 \cf0 \ diff --git a/OSX/grabclient-osx.m b/OSX/grabclient-osx.m index e29e8da1..ca30251e 100644 --- a/OSX/grabclient-osx.m +++ b/OSX/grabclient-osx.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright © 1992-2021 Jamie Zawinski +/* xscreensaver, Copyright © 1992-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -65,10 +65,74 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, } -#else /* macOS 10.5+ */ +#else /* !HAVE_IPHONE */ extern float jwxyz_scale (Window); /* jwxyzI.h */ +static void +authorize_screen_capture (void) +{ + static Bool done_once = False; + if (done_once) return; + done_once = True; + + /* The following nonsense is intended to get the system to pop up the dialog + saying "do you want to allow legacyScreenSaver to be able to record your + screen?" Without the user saying yes to that, we are only able to get + the desktop background image instead of a screen shot. Also this is + async, so if that dialog has popped up, the *current* screen grab will + still fail. + + To reset answers given to that dialog: "tccutil reset ScreenCapture". + + Sadly, this is not working at all. If the .saver bundle is launched by + SaverTester, the dialog is triggered on behalf of SaverTester, and works. + But if it the bundle is launched by the real screen saver, or by System + Preferences, the dialog is not triggered. + + Manually dragging "/System/Library/Frameworks/ScreenSaver.framework/ + PlugIns/legacyScreenSaver.appex" onto the "System Preferences / Security / + Privacy / Screen Recording" list makes screen grabbing work, but that's + a lot to ask of the end user. And, oddly, after dragging it there, it + does not appear in the list at all (and there's no way to un-check it). + + We can open that preferences pane with + "open x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture" + but there's no way to auto-add legacyScreenSaver to it, even unchecked. + */ + +# if 1 + /* CGDisplayStreamRef stream = */ /* Just leak it, I guess? */ + CGDisplayStreamCreateWithDispatchQueue (CGMainDisplayID(), + 1, 1, kCVPixelFormatType_32BGRA, + nil, + dispatch_get_main_queue(), + nil); + /* I think that if the returned value is nil, it means the screen grab + will be returning just the background image instead of the desktop. + So in that case we could return False here to go with colorbars. + But the desktop background image is still more interesting than + colorbars, so let's just use that. */ + +# elif 0 + /* This also does not work. */ + if (@available (macos 10.15, *)) { + CGImageRef img = + CGWindowListCreateImage (CGRectMake(0, 0, 1, 1), + kCGWindowListOptionOnScreenOnly, + kCGNullWindowID, + kCGWindowImageDefault); + CFRelease (img); + } + +# elif 0 + /* This also does not work. */ + if (@available (macos 10.15, *)) + CGRequestScreenCaptureAccess(); +# endif +} + + /* Loads an image into the Drawable, returning once the image is loaded. */ Bool @@ -81,6 +145,8 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, int window_x, window_y; Window unused; + authorize_screen_capture(); + // Figure out where this window is on the screen. // XGetWindowAttributes (dpy, xwindow, &xgwa); @@ -96,44 +162,6 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, cgrect.size.width = xgwa.width / s; cgrect.size.height = xgwa.height / s; - /* The following nonsense is intended to get the system to pop up the dialog - saying "do you want to allow legacyScreenSaver to be able to record your - screen?" Without the user saying yes to that, we are only able to get - the desktop background image instead of a screen shot. Also this is - async, so if that dialog has popped up, the *current* screen grab will - still fail. - - To reset answers given to that dialog: "tccutil reset ScreenCapture". - - Sadly, this is not working at all. If the .saver bundle is launched by - SaverTester, the dialog is triggered on behalf of SaverTester, but it is - not triggered on behalf of ScreenSaverEngine or System Preferences. - - Manually dragging "/System/Library/Frameworks/ScreenSaver.framework/ - PlugIns/legacyScreenSaver.appex" onto the "System Preferences / Security / - Privacy / Screen Recording" list makes screen grabbing work, but that's - a lot to ask of the end user. And, oddly, after dragging it there, it - does not appear in the list. - */ - { - static Bool done_once = False; - if (! done_once) { - done_once = True; - /* CGDisplayStreamRef stream = */ /* Just leak it, I guess? */ - CGDisplayStreamCreateWithDispatchQueue (CGMainDisplayID(), - 1, 1, kCVPixelFormatType_32BGRA, - nil, - dispatch_get_main_queue(), - nil); - /* I think that if the returned value is nil, it means the screen grab - will be returning just the background image instead of the desktop. - So in that case we could return False here to go with colorbars. - But the desktop background image is still more interesting than - colorbars, so let's just use that. */ - } - } - - CGWindowID windowNumber = (CGWindowID) nsview.window.windowNumber; /* If a password is required to unlock the screen, a large black @@ -145,8 +173,8 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, Oct 2016: Surprise, this trick no longer works on MacOS 10.12. Sigh. - Nov 2021, macOS 11.6, 12.0: I'm pretty sure none of this works this way - any more, and so probably the following clause is no longer necessary? + Nov 2021, macOS 11.6, 12.0: This works again. Without the following + clause, we do indeed grab a black image. */ { CFArrayRef L = CGWindowListCopyWindowInfo (kCGWindowListOptionOnScreenOnly, @@ -185,20 +213,7 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, return True; } - -/* Returns the EXIF rotation property of the image, if any. - */ -static int -exif_rotation (const char *filename) -{ - /* As of 10.6, NSImage rotates according to EXIF by default: - http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html - Prior to that, we had to do it by hand. - */ - return -1; -} - -# endif /* macOS 10.5+ */ +# endif /* !HAVE_IPHONE */ @@ -222,8 +237,7 @@ osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable, return False; jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable, - True, img, geom_ret, - exif_rotation (filename)); + True, img, geom_ret, -1); [img release]; return True; diff --git a/README b/README index 53490feb..3bd28c7d 100644 --- a/README +++ b/README @@ -33,14 +33,13 @@ To compile for a Unix system with X11: xscreensaver & xscreensaver-settings - There are many compilation dependencies. The configure script will - tell you what is missing. At the least, you will need development - versions of these libraries: + There are many compilation dependencies. The configure script will tell + you what is missing. At the least, you will need development versions of + these libraries. Append "-dev" or "-devel" to most of these: perl pkg-config gettext intltool libx11 libxext libxi libxt libxft - libxinerama libxrandr libxxf86vm libgl libglu libgle libgtk2.0 - libgdk-pixbuf2.0 libgdk-pixbuf-xlib-2.0 libjpeg libxml2 libpam - libsystemd elogind + libxinerama libxrandr libxxf86vm libgl libglu libgle libgtk-3-0 + libgdk-pixbuf2.0 libjpeg libxml2 libpam libsystemd elogind BSD systems might need gmake instead of make. @@ -70,6 +69,14 @@ Interested in writing a new screen saver? Version History =============================================================================== +6.05 * X11: Cope with dumb DPMS settings that existed pre-startup. + * X11: Silence new Perl warnings from `xscreensaver-getimage-file'. + * X11: Fix `sonar' pthreads crash on recent Pi systems. + * X11: Removed dependence on `gdk-pixbuf-xlib-2.0'. + * X11: GTK 3 is now required. + * macOS: Fixed the "Run savers on screens" preference in Random mode + on multi-screen M1 systems. + 6.04 * New hacks, `nakagin' and `chompytower'. * Settings dialog shows diagnostics for bad image folders and feeds. * URLs for `imageDirectory' can now point at archive.org collections. @@ -1738,7 +1745,7 @@ Version History the parameters which are normally read as minutes can be specified in seconds. * Added colormap cycling to `imsmap'. - * Made hyper work with K&R compilers. + * Made `hyper' work with K&R compilers. 1.14 * Added `orbit' option to `attraction' hack. * Added `lock-timeout' option. @@ -1747,14 +1754,26 @@ Version History 1.09 * Added demo mode, and locking. * Added `maze' hack. * Added `norotate' option to `rocks' hack. + * Uploaded to export.lcs.mit.edu:contrib/xscreensaver.tar.Z and posted + to comp.windows.x.announce, 25-Feb-1993. + * Added `hypercube' and `slidescreen' (or they may have been added + earlier). 1.05 * Works when run from XDM before anyone logs in. * Sped up `imsmap'. * Can use `xv' as a slideshow without using up colormap entries while the screen is not blanked. * Fixed a BadDrawable error in non-XIdle mode. - * Added `blitspin' and `imsmap'. + * Uploaded to export.lcs.mit.edu:contrib/xsaver.tar.Z and posted to + comp.windows.x.announce, 30-Nov-1992. + +1.04 * Added `blitspin' and `imsmap' (or they may have been earlier). + * Appeared on the X11R5 contrib tape, a mirror of export.lcs.mit.edu, + 29-Nov-1992. + +1.00 * Uploaded to export.lcs.mit.edu:contrib/xsaver.tar.Z and posted to + comp.windows.x.announce, 17-Aug-1992. + * Initial list of included hacks: + `qix', `helix', `rorschach', `attraction', `greynetic', `rocks', + `pyro', `hopalong', and `noseguy'. -1.01 * Current list of included hacks is now: `qix', `helix', `rorschach', - `attraction', `greynetic', `rocks', `pyro', `hopalong', and - `noseguy'. diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 5c7399ac..0df0bebb 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip diff --git a/config.h.in b/config.h.in index 1fb47690..568c0ce3 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,7 @@ /* config.h.in. Generated from configure.ac by autoheader. */ -/* xscreensaver, Copyright © 1991-2021 Jamie Zawinski. +/* xscreensaver, Copyright © 1991-2022 Jamie Zawinski. * Generate this file by running 'configure' rather than editing it by hand. */ @@ -59,13 +59,16 @@ /* Define this if you have forkpty. */ #undef HAVE_FORKPTY -/* Define this if you have GDK_Pixbuf. */ +/* Define this if you have GDK-Pixbuf. */ #undef HAVE_GDK_PIXBUF /* Define this if you have the gdk_pixbuf_apply_embedded_orientation function (gdk-pixbuf 2.12). */ #undef HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION +/* Define this if you have GDK-Pixbuf-Xlib. */ +#undef HAVE_GDK_PIXBUF_XLIB + /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO @@ -108,11 +111,8 @@ /* Define this if OpenGL supports the OpenGL Shading Language. */ #undef HAVE_GLSL -/* Define this if you have Gtk */ -#undef HAVE_GTK - /* Define this if you have Gtk 2.x. */ -#undef HAVE_GTK2 +#undef HAVE_GTK /* Define this for HPUX so-called "Secure Passwords". */ #undef HAVE_HPUX_PASSWD diff --git a/configure b/configure index 1b945a13..c087577a 100755 --- a/configure +++ b/configure @@ -683,6 +683,7 @@ NEW_LOGIN_COMMAND_P NEW_LOGIN_COMMAND COMMENT_PAM_CHECK_ACCOUNT HAVE_PAM_FAIL_DELAY +GLIB_COMPILE_RESOURCES INSTALL_PAM INSTALL_DIRS SETCAP_HACKS @@ -6720,6 +6721,9 @@ printf "%s\n" "$ac_macosx" >&6; } # ############################################################################### +# Note: In the decades since I wrote this, PKG_CHECK_MODULES came into +# existence, which could probably simplify the following quite a bit. + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 @@ -14981,13 +14985,14 @@ gtk_halfassed=no if test "$with_gtk" = yes; then have_gtk=no + pkgs='' ok="yes" - pkg_check_version gtk+-2.0 2.22.0 ; ac_gtk_version_string="$vers" - pkg_check_version gmodule-2.0 2.0.0 - pkg_check_version libxml-2.0 2.4.6 - pkg_check_version gdk-pixbuf-2.0 2.0.0 - pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 + pkg_check_version gtk+-3.0 2.22.0 ; ac_gtk_version_string="$vers" + pkg_check_version gmodule-2.0 2.0.0 + pkg_check_version libxml-2.0 2.4.6 + pkg_check_version gdk-pixbuf-2.0 2.0.0 have_gtk="$ok" + gtk_pkgs="$pkgs" if test "$have_gtk" = no; then if test -n "$ac_gtk_version_string" ; then @@ -15033,11 +15038,24 @@ printf "%s\n" "$ac_cv_gtk_config_libs" >&6; } GTK_LIBS="$GTK_LIBS $ac_gtk_config_libs" printf "%s\n" "#define HAVE_GTK 1" >>confdefs.h - printf "%s\n" "#define HAVE_GTK2 1" >>confdefs.h - printf "%s\n" "#define HAVE_XML 1" >>confdefs.h fi + + if test "$have_gtk" = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Glib resource compiler" >&5 +printf %s "checking for Glib resource compiler... " >&6; } +if test ${ac_cv_glib_res+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_glib_res=`$pkg_config --variable=glib_compile_resources gio-2.0` +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_glib_res" >&5 +printf "%s\n" "$ac_cv_glib_res" >&6; } + GLIB_COMPILE_RESOURCES="$ac_cv_glib_res" + fi + fi # Check for the various Gnome help and URL loading programs. @@ -19016,6 +19034,7 @@ fi ############################################################################### have_gdk_pixbuf=no +have_gdk_pixbuf_xlib=no with_gdk_pixbuf_req=unspecified # Check whether --with-pixbuf was given. @@ -19090,11 +19109,10 @@ if test "$with_gdk_pixbuf" = yes; then pkgs='' ok="yes" - - pkg_check_version gdk-pixbuf-2.0 2.0.0 - pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 - pkg_check_version gio-2.0 2.0.0 + pkg_check_version gdk-pixbuf-2.0 2.0.0 + pkg_check_version gio-2.0 2.0.0 have_gdk_pixbuf="$ok" + pixbuf_pkgs="$pkgs" if test "$have_gdk_pixbuf" = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdk-pixbuf includes" >&5 @@ -19128,11 +19146,8 @@ printf "%s\n" "$ac_cv_gdk_pixbuf_config_libs" >&6; } # ac_save_gdk_pixbuf_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $ac_gdk_pixbuf_config_cflags" - have_gdk_pixbuf=no - # check for header A... - ac_save_CPPFLAGS="$CPPFLAGS" if test \! -z "$includedir" ; then CPPFLAGS="$CPPFLAGS -I$includedir" @@ -19146,61 +19161,15 @@ then : fi CPPFLAGS="$ac_save_CPPFLAGS" - - # if that worked, check for header B... - if test "$have_gdk_pixbuf" = yes; then - have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - - ac_save_CPPFLAGS="$CPPFLAGS" - if test \! -z "$includedir" ; then - CPPFLAGS="$CPPFLAGS -I$includedir" - fi - CPPFLAGS="$CPPFLAGS $X_CFLAGS" - CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS` - ac_fn_c_check_header_compile "$LINENO" "gdk-pixbuf/gdk-pixbuf-xlib.h" "ac_cv_header_gdk_pixbuf_gdk_pixbuf_xlib_h" "$ac_includes_default" -if test "x$ac_cv_header_gdk_pixbuf_gdk_pixbuf_xlib_h" = xyes -then : - have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no -fi - - CPPFLAGS="$ac_save_CPPFLAGS" - - # yay, it has a new name in Gtk 2.x... - if test "$have_gdk_pixbuf" = no; then - have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - - ac_save_CPPFLAGS="$CPPFLAGS" - if test \! -z "$includedir" ; then - CPPFLAGS="$CPPFLAGS -I$includedir" - fi - CPPFLAGS="$CPPFLAGS $X_CFLAGS" - CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS` - ac_fn_c_check_header_compile "$LINENO" "gdk-pixbuf-xlib/gdk-pixbuf-xlib.h" "ac_cv_header_gdk_pixbuf_xlib_gdk_pixbuf_xlib_h" "$ac_includes_default" -if test "x$ac_cv_header_gdk_pixbuf_xlib_gdk_pixbuf_xlib_h" = xyes -then : - have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no -fi - - CPPFLAGS="$ac_save_CPPFLAGS" - fi - fi CPPFLAGS="$ac_save_gdk_pixbuf_CPPFLAGS" fi if test "$have_gdk_pixbuf" = yes; then # we have the headers, now check for the libraries have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: checking for gdk_pixbuf usability..." >&5 printf "%s\n" "checking for gdk_pixbuf usability..." >&6; } - # library A... - ac_save_CPPFLAGS="$CPPFLAGS" ac_save_LDFLAGS="$LDFLAGS" # ac_save_LIBS="$LIBS" @@ -19263,74 +19232,6 @@ fi LDFLAGS="$ac_save_LDFLAGS" # LIBS="$ac_save_LIBS" - # library B... - if test "$have_gdk_pixbuf" = yes; then - have_gdk_pixbuf=no - - ac_save_CPPFLAGS="$CPPFLAGS" - ac_save_LDFLAGS="$LDFLAGS" -# ac_save_LIBS="$LIBS" - - if test \! -z "$includedir" ; then - CPPFLAGS="$CPPFLAGS -I$includedir" - fi - # note: $X_CFLAGS includes $x_includes - CPPFLAGS="$CPPFLAGS $X_CFLAGS" - - if test \! -z "$libdir" ; then - LDFLAGS="$LDFLAGS -L$libdir" - fi - # note: $X_LIBS includes $x_libraries - LDFLAGS="$LDFLAGS $X_LIBS $X_EXTRA_LIBS" - - CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS` - LDFLAGS=`eval eval eval eval eval eval eval eval eval echo $LDFLAGS` - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdk_pixbuf_xlib_init in -lc" >&5 -printf %s "checking for gdk_pixbuf_xlib_init in -lc... " >&6; } -if test ${ac_cv_lib_c_gdk_pixbuf_xlib_init+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lc $ac_gdk_pixbuf_config_libs -lX11 -lXext -lm $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gdk_pixbuf_xlib_init (); -int -main (void) -{ -return gdk_pixbuf_xlib_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_c_gdk_pixbuf_xlib_init=yes -else $as_nop - ac_cv_lib_c_gdk_pixbuf_xlib_init=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_gdk_pixbuf_xlib_init" >&5 -printf "%s\n" "$ac_cv_lib_c_gdk_pixbuf_xlib_init" >&6; } -if test "x$ac_cv_lib_c_gdk_pixbuf_xlib_init" = xyes -then : - have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no -fi - - CPPFLAGS="$ac_save_CPPFLAGS" - LDFLAGS="$ac_save_LDFLAGS" -# LIBS="$ac_save_LIBS" - - fi fi if test "$have_gdk_pixbuf" = yes; then @@ -19411,6 +19312,68 @@ fi fi fi +# Now that we have checked for gdk_pixbuf, check for gdk_pixbuf_xlib +# separately, since it has fallen out of fashion in recent years. +# +#have_gdk_pixbuf_xlib=no +#gdk_pixbuf_xlib_halfassed=no +#if test "$with_gdk_pixbuf" = yes -a "$have_gdk_pixbuf" = yes; then +# +# have_gdk_pixbuf_xlib=no +# pkgs="$pixbuf_pkgs" +# ok="yes" +# pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 +# pkg_check_version gdk-pixbuf-2.0 2.0.0 +# have_gdk_pixbuf_xlib="$ok" +# pixbuf_xlib_pkgs="$pkgs" +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# AC_CACHE_CHECK([for gdk-pixbuf-xlib includes], +# ac_cv_gdk_pixbuf_xlib_config_cflags, +# [ac_cv_gdk_pixbuf_xlib_config_cflags=`$pkg_config --cflags $pkgs`]) +# AC_CACHE_CHECK([for gdk-pixbuf-xlib libs], +# ac_cv_gdk_pixbuf_xlib_config_libs, +# [ac_cv_gdk_pixbuf_xlib_config_libs=`$pkg_config --libs $pkgs`]) +# fi +# +# ac_gdk_pixbuf_xlib_config_cflags=$ac_cv_gdk_pixbuf_xlib_config_cflags +# ac_gdk_pixbuf_xlib_config_libs=$ac_cv_gdk_pixbuf_xlib_config_libs +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# # +# # we appear to have pixbuf_xlib; check for headers/libs to be sure. +# # +# ac_save_gdk_pixbuf_xlib_CPPFLAGS="$CPPFLAGS" +# CPPFLAGS="$CPPFLAGS $ac_gdk_pixbuf_xlib_config_cflags" +# have_gdk_pixbuf_xlib=no +# gdk_pixbuf_xlib_halfassed=yes +# AC_CHECK_X_HEADER(gdk-pixbuf-xlib/gdk-pixbuf-xlib.h, +# [have_gdk_pixbuf_xlib=yes +# gdk_pixbuf_xlib_halfassed=no]) +# CPPFLAGS="$ac_save_gdk_pixbuf_xlib_CPPFLAGS" +# fi +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# # we have the headers, now check for the libraries +# have_gdk_pixbuf_xlib=no +# gdk_pixbuf_xlib_halfassed=yes +# +# AC_MSG_RESULT(checking for gdk_pixbuf_xlib usability...) +# AC_CHECK_X_LIB(c, gdk_pixbuf_xlib_init, +# [have_gdk_pixbuf_xlib=yes +# gdk_pixbuf_xlib_halfassed=no],, +# $ac_gdk_pixbuf_xlib_config_libs -lX11 -lXext -lm) +# fi +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# INCLUDES="$INCLUDES $ac_gdk_pixbuf_xlib_config_cflags" +# PNG_LIBS="$ac_gdk_pixbuf_xlib_config_libs" +# AC_DEFINE(HAVE_GDK_PIXBUF_XLIB) +# else +# AC_MSG_RESULT(checking for gdk_pixbuf_xlib usability... no) +# fi +#fi + ############################################################################### # # Check for -lXft @@ -21799,13 +21762,6 @@ if test "$gtk_halfassed" != no ; then warnL "GTK was found, but $gtk_halfassed_lib was not, so GTK" warn2 "can't be used." CONF_STATUS=1 - - if ( echo $gtk_halfassed_lib | grep -qi pixbuf-xlib ); then - echo '' - warn2 "Recently, some distros have stopped distributing" - warn2 "gdk-pixbuf-xlib entirely. So good luck with that." - fi - fi motif_warn2() { @@ -21890,8 +21846,7 @@ if test "$with_gdk_pixbuf_req" = yes -a "$have_gdk_pixbuf" = no; then CONF_STATUS=1 fi -if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes || \ - test "$have_gdk_pixbuf" = no ; then +if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes ; then if test "$with_gdk_pixbuf_req" = yes ; then true @@ -21913,6 +21868,25 @@ if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes || \ warn2 'configure.' fi +#if test "$have_gdk_pixbuf" = yes -a "$have_gdk_pixbuf_xlib" = no ; then +# +# warnL 'The GDK-Pixbuf-Xlib library was not found.' +# +# if test "$gdk_pixbuf_xlib_halfassed" = yes ; then halfassery ; fi +# if test "$have_png" = yes ; then +# echo '' +# warn2 'The PNG library is being used instead.' +# fi +# +# echo '' +# warn2 'Some of the demos will not use images as much as they could.' +# warn2 'You should consider installing GDK-Pixbuf-Xlib and re-running' +# warn2 'configure.' +# echo '' +# warn2 "Recently, some distros have stopped distributing" +# warn2 "GDK-Pixbuf-Xlib entirely. So good luck with that." +#fi + if test "$have_jpeg" = no ; then if test "$with_jpeg_req" = yes ; then warnL 'Use of libjpeg was requested, but it was not found.' diff --git a/configure.ac b/configure.ac index 1c143b24..9998d051 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ fi ############################################################################### AH_TOP([ -/* xscreensaver, Copyright © 1991-2021 Jamie Zawinski. +/* xscreensaver, Copyright © 1991-2022 Jamie Zawinski. * Generate this file by running 'configure' rather than editing it by hand. */ ]) @@ -163,15 +163,15 @@ AH_TEMPLATE([HAVE_XMCOMBOBOX], [Define this if you have the XmComboBox Motif 2.0 widget.]) AH_TEMPLATE([HAVE_GTK], - [Define this if you have Gtk]) -AH_TEMPLATE([HAVE_GTK2], [Define this if you have Gtk 2.x.]) AH_TEMPLATE([HAVE_XML], [Define this if you have the XML library.]) AH_TEMPLATE([HAVE_GDK_PIXBUF], - [Define this if you have GDK_Pixbuf.]) + [Define this if you have GDK-Pixbuf.]) +AH_TEMPLATE([HAVE_GDK_PIXBUF_XLIB], + [Define this if you have GDK-Pixbuf-Xlib.]) AH_TEMPLATE([HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION], [Define this if you have the gdk_pixbuf_apply_embedded_orientation @@ -1127,6 +1127,9 @@ AC_MSG_RESULT($ac_macosx) # ############################################################################### +# Note: In the decades since I wrote this, PKG_CHECK_MODULES came into +# existence, which could probably simplify the following quite a bit. + AC_PATH_TOOL(pkg_config, pkg-config) if test -z "$pkg_config" ; then @@ -2791,13 +2794,14 @@ gtk_halfassed=no if test "$with_gtk" = yes; then have_gtk=no + pkgs='' ok="yes" - pkg_check_version gtk+-2.0 2.22.0 ; ac_gtk_version_string="$vers" - pkg_check_version gmodule-2.0 2.0.0 - pkg_check_version libxml-2.0 2.4.6 - pkg_check_version gdk-pixbuf-2.0 2.0.0 - pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 + pkg_check_version gtk+-3.0 2.22.0 ; ac_gtk_version_string="$vers" + pkg_check_version gmodule-2.0 2.0.0 + pkg_check_version libxml-2.0 2.4.6 + pkg_check_version gdk-pixbuf-2.0 2.0.0 have_gtk="$ok" + gtk_pkgs="$pkgs" if test "$have_gtk" = no; then if test -n "$ac_gtk_version_string" ; then @@ -2826,9 +2830,15 @@ if test "$with_gtk" = yes; then INCLUDES="$INCLUDES $ac_gtk_config_cflags" GTK_LIBS="$GTK_LIBS $ac_gtk_config_libs" AC_DEFINE(HAVE_GTK) - AC_DEFINE(HAVE_GTK2) AC_DEFINE(HAVE_XML) fi + + if test "$have_gtk" = yes; then + AC_CACHE_CHECK([for Glib resource compiler], ac_cv_glib_res, + [ac_cv_glib_res=`$pkg_config --variable=glib_compile_resources gio-2.0`]) + GLIB_COMPILE_RESOURCES="$ac_cv_glib_res" + fi + fi @@ -3779,6 +3789,7 @@ fi ############################################################################### have_gdk_pixbuf=no +have_gdk_pixbuf_xlib=no with_gdk_pixbuf_req=unspecified AC_ARG_WITH(pixbuf, [ --with-pixbuf Include support for the GDK-Pixbuf library, which @@ -3809,11 +3820,10 @@ if test "$with_gdk_pixbuf" = yes; then pkgs='' ok="yes" - - pkg_check_version gdk-pixbuf-2.0 2.0.0 - pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 - pkg_check_version gio-2.0 2.0.0 + pkg_check_version gdk-pixbuf-2.0 2.0.0 + pkg_check_version gio-2.0 2.0.0 have_gdk_pixbuf="$ok" + pixbuf_pkgs="$pkgs" if test "$have_gdk_pixbuf" = yes; then AC_CACHE_CHECK([for gdk-pixbuf includes], ac_cv_gdk_pixbuf_config_cflags, @@ -3832,50 +3842,17 @@ if test "$with_gdk_pixbuf" = yes; then # ac_save_gdk_pixbuf_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $ac_gdk_pixbuf_config_cflags" - have_gdk_pixbuf=no - - # check for header A... AC_CHECK_X_HEADER(gdk-pixbuf/gdk-pixbuf.h, [have_gdk_pixbuf=yes]) - - # if that worked, check for header B... - if test "$have_gdk_pixbuf" = yes; then - have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - AC_CHECK_X_HEADER(gdk-pixbuf/gdk-pixbuf-xlib.h, - [have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no]) - - # yay, it has a new name in Gtk 2.x... - if test "$have_gdk_pixbuf" = no; then - have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - AC_CHECK_X_HEADER(gdk-pixbuf-xlib/gdk-pixbuf-xlib.h, - [have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no]) - fi - fi CPPFLAGS="$ac_save_gdk_pixbuf_CPPFLAGS" fi if test "$have_gdk_pixbuf" = yes; then # we have the headers, now check for the libraries have_gdk_pixbuf=no - gdk_pixbuf_halfassed=yes - AC_MSG_RESULT(checking for gdk_pixbuf usability...) - - # library A... AC_CHECK_X_LIB(c, gdk_pixbuf_new_from_file, [have_gdk_pixbuf=yes],, $ac_gdk_pixbuf_config_libs -lX11 -lXext -lm) - # library B... - if test "$have_gdk_pixbuf" = yes; then - have_gdk_pixbuf=no - AC_CHECK_X_LIB(c, gdk_pixbuf_xlib_init, - [have_gdk_pixbuf=yes - gdk_pixbuf_halfassed=no],, - $ac_gdk_pixbuf_config_libs -lX11 -lXext -lm) - fi fi if test "$have_gdk_pixbuf" = yes; then @@ -3894,6 +3871,69 @@ if test "$with_gdk_pixbuf" = yes; then fi +# Now that we have checked for gdk_pixbuf, check for gdk_pixbuf_xlib +# separately, since it has fallen out of fashion in recent years. +# +#have_gdk_pixbuf_xlib=no +#gdk_pixbuf_xlib_halfassed=no +#if test "$with_gdk_pixbuf" = yes -a "$have_gdk_pixbuf" = yes; then +# +# have_gdk_pixbuf_xlib=no +# pkgs="$pixbuf_pkgs" +# ok="yes" +# pkg_check_version gdk-pixbuf-xlib-2.0 2.0.0 +# pkg_check_version gdk-pixbuf-2.0 2.0.0 +# have_gdk_pixbuf_xlib="$ok" +# pixbuf_xlib_pkgs="$pkgs" +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# AC_CACHE_CHECK([for gdk-pixbuf-xlib includes], +# ac_cv_gdk_pixbuf_xlib_config_cflags, +# [ac_cv_gdk_pixbuf_xlib_config_cflags=`$pkg_config --cflags $pkgs`]) +# AC_CACHE_CHECK([for gdk-pixbuf-xlib libs], +# ac_cv_gdk_pixbuf_xlib_config_libs, +# [ac_cv_gdk_pixbuf_xlib_config_libs=`$pkg_config --libs $pkgs`]) +# fi +# +# ac_gdk_pixbuf_xlib_config_cflags=$ac_cv_gdk_pixbuf_xlib_config_cflags +# ac_gdk_pixbuf_xlib_config_libs=$ac_cv_gdk_pixbuf_xlib_config_libs +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# # +# # we appear to have pixbuf_xlib; check for headers/libs to be sure. +# # +# ac_save_gdk_pixbuf_xlib_CPPFLAGS="$CPPFLAGS" +# CPPFLAGS="$CPPFLAGS $ac_gdk_pixbuf_xlib_config_cflags" +# have_gdk_pixbuf_xlib=no +# gdk_pixbuf_xlib_halfassed=yes +# AC_CHECK_X_HEADER(gdk-pixbuf-xlib/gdk-pixbuf-xlib.h, +# [have_gdk_pixbuf_xlib=yes +# gdk_pixbuf_xlib_halfassed=no]) +# CPPFLAGS="$ac_save_gdk_pixbuf_xlib_CPPFLAGS" +# fi +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# # we have the headers, now check for the libraries +# have_gdk_pixbuf_xlib=no +# gdk_pixbuf_xlib_halfassed=yes +# +# AC_MSG_RESULT(checking for gdk_pixbuf_xlib usability...) +# AC_CHECK_X_LIB(c, gdk_pixbuf_xlib_init, +# [have_gdk_pixbuf_xlib=yes +# gdk_pixbuf_xlib_halfassed=no],, +# $ac_gdk_pixbuf_xlib_config_libs -lX11 -lXext -lm) +# fi +# +# if test "$have_gdk_pixbuf_xlib" = yes; then +# INCLUDES="$INCLUDES $ac_gdk_pixbuf_xlib_config_cflags" +# PNG_LIBS="$ac_gdk_pixbuf_xlib_config_libs" +# AC_DEFINE(HAVE_GDK_PIXBUF_XLIB) +# else +# AC_MSG_RESULT(checking for gdk_pixbuf_xlib usability... no) +# fi +#fi + + ############################################################################### # # Check for -lXft @@ -4306,6 +4346,7 @@ AC_SUBST(SETUID_HACKS) AC_SUBST(SETCAP_HACKS) AC_SUBST(INSTALL_DIRS) AC_SUBST(INSTALL_PAM) +AC_SUBST(GLIB_COMPILE_RESOURCES) AC_SUBST(HAVE_PAM_FAIL_DELAY) AC_SUBST(COMMENT_PAM_CHECK_ACCOUNT) AC_SUBST(NEW_LOGIN_COMMAND) @@ -4528,13 +4569,6 @@ if test "$gtk_halfassed" != no ; then warnL "GTK was found, but $gtk_halfassed_lib was not, so GTK" warn2 "can't be used." CONF_STATUS=1 - - if ( echo $gtk_halfassed_lib | grep -qi pixbuf-xlib ); then - echo '' - warn2 "Recently, some distros have stopped distributing" - warn2 "gdk-pixbuf-xlib entirely. So good luck with that." - fi - fi motif_warn2() { @@ -4621,8 +4655,7 @@ if test "$with_gdk_pixbuf_req" = yes -a "$have_gdk_pixbuf" = no; then CONF_STATUS=1 fi -if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes || \ - test "$have_gdk_pixbuf" = no ; then +if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes ; then if test "$with_gdk_pixbuf_req" = yes ; then true @@ -4645,6 +4678,26 @@ if test "$have_gdk_pixbuf" = no -o "$gdk_pixbuf_halfassed" = yes || \ fi +#if test "$have_gdk_pixbuf" = yes -a "$have_gdk_pixbuf_xlib" = no ; then +# +# warnL 'The GDK-Pixbuf-Xlib library was not found.' +# +# if test "$gdk_pixbuf_xlib_halfassed" = yes ; then halfassery ; fi +# if test "$have_png" = yes ; then +# echo '' +# warn2 'The PNG library is being used instead.' +# fi +# +# echo '' +# warn2 'Some of the demos will not use images as much as they could.' +# warn2 'You should consider installing GDK-Pixbuf-Xlib and re-running' +# warn2 'configure.' +# echo '' +# warn2 "Recently, some distros have stopped distributing" +# warn2 "GDK-Pixbuf-Xlib entirely. So good luck with that." +#fi + + if test "$have_jpeg" = no ; then if test "$with_jpeg_req" = yes ; then warnL 'Use of libjpeg was requested, but it was not found.' diff --git a/driver/.gdbinit b/driver/.gdbinit deleted file mode 100644 index a585259f..00000000 --- a/driver/.gdbinit +++ /dev/null @@ -1,27 +0,0 @@ -# If you're debugging xscreensaver and you are running a virtual root window -# manager, you'd better let the process handle these signals: it remaps the -# virtual root window when they arrive. If you don't do this, your window -# manager will be hosed. -# -# Also, gdb copes badly with breakpoints in functions that are called on the -# other side of a fork(). The Trace/BPT traps cause the spawned process to -# die. -# -#handle 1 pass nostop -#handle 3 pass nostop -#handle 4 pass nostop -#handle 6 pass nostop -#handle 7 pass nostop -#handle 8 pass nostop -#handle 9 pass nostop -#handle 10 pass nostop -#handle 11 pass nostop -#handle 12 pass nostop -#handle 13 pass nostop -#handle 15 pass nostop -#handle 19 pass nostop -set env MallocGuardEdges 1 -set env MallocPreScribble 1 -set env MallocScribble 1 -b exit -set args -debug diff --git a/driver/Makefile.in b/driver/Makefile.in index e1fa1b22..c25494ac 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -30,7 +30,8 @@ GTK_DATADIR = @GTK_DATADIR@ GTK_APPDIR = $(GTK_DATADIR)/applications GTK_ICONDIR = $(GTK_DATADIR)/pixmaps GTK_SHAREDIR = $(GTK_DATADIR)/xscreensaver -GTK_UIDIR = $(GTK_SHAREDIR)/ui +UPDATE_ICON_CACHE = gtk-update-icon-cache +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ HACKDIR = @HACKDIR@ HACK_CONF_DIR = @HACK_CONF_DIR@ @@ -84,7 +85,6 @@ PAM_CONF = $(PAM_ROOT)/pam.conf ICON_SRC = $(UTILS_SRC)/images LOGO = $(ICON_SRC)/logo-512.png -GTK_ICONS = $(ICON_SRC)/screensaver-*.png UTILS_SRC = $(srcdir)/../utils UTILS_BIN = ../utils @@ -159,7 +159,7 @@ AUTH_OBJS_1 = dialog.o passwd.o setuid.o \ $(UTILS_BIN)/logo.o \ $(UTILS_BIN)/minixpm.o AUTH_LIBS = $(LIBS_PRE) $(XFT_LIBS) $(XINPUT_LIBS) $(XINERAMA_LIBS) \ - @SAVER_LIBS@ -lXt -lX11 -lXext -lXi \ + $(XDPMS_LIBS) @SAVER_LIBS@ -lXt -lX11 -lXext -lXi \ @PASSWD_LIBS@ $(LIBS_POST) $(INTL_LIBS) SYSTEMD_DEFS = @@ -174,11 +174,10 @@ CMD_LIBS = $(LIBS_PRE) $(XINPUT_LIBS) -lX11 -lXext $(LIBS_POST) GTK_DEFS = -DHACK_CONFIGURATION_PATH='"$(HACK_CONF_DIR)"' \ -DDEFAULT_PATH_PREFIX='"@HACKDIR@"' \ - -DDEFAULT_ICONDIR='"$(GTK_UIDIR)"' \ -DLOCALEDIR=\"$(localedir)\" \ -I$(ICON_SRC) GTK_SRCS = demo-Gtk.c demo-Gtk-conf.c -GTK_OBJS = demo-Gtk.o demo-Gtk-conf.o \ +GTK_OBJS = demo-Gtk.o demo-Gtk-conf.o demo-Gtk-resources.o \ blurb.o exec.o prefs.o prefsw.o dpms.o remote.o screens.o \ clientmsg.o atoms.o \ $(UTILS_BIN)/xmu.o \ @@ -229,8 +228,8 @@ MENB = xscreensaver-gfx.man xscreensaver-auth.man \ EXTRAS = README Makefile.in \ XScreenSaver.ad.in XScreenSaver-Xm.ad xscreensaver.pam.in \ - xscreensaver.ui xscreensaver-settings.desktop.in \ - xscreensaver.desktop.in xscreensaver.service.in .gdbinit + demo.ui prefs.ui gresource.xml xscreensaver.desktop.in \ + xscreensaver-settings.desktop.in xscreensaver.service.in TARFILES = $(DAEMON_SRCS) $(GFX_SRCS) $(AUTH_SRCS) $(SYSTEMD_SRCS) \ $(CMD_SRCS) $(GTK_SRCS) $(MOTIF_SRCS) $(PWENT_SRCS) \ @@ -536,6 +535,10 @@ install-gnome:: xscreensaver.desktop xscreensaver-settings.desktop # xscreensaver.service # into /usr/share/xscreensaver/ +# But maybe it should instead be installed as: +# $(prefix)/share/dbus-1/system-services/org.jwz.xscreensaver.service +# Or would that make it be enabled by default? +# install-gnome:: xscreensaver.service @if [ ! -d "$(install_prefix)$(GTK_SHAREDIR)" ]; then \ echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_SHAREDIR)" ;\ @@ -560,55 +563,21 @@ install-gnome:: $(LOGO) $(install_prefix)$(GTK_ICONDIR)/$$target ;\ fi -# ../utils/images/screensaver-*.png -# into /usr/share/xscreensaver/ui/ -install-gnome:: - @if [ "$(GTK_DATADIR)" != "" ]; then \ - if [ ! -d "$(install_prefix)$(GTK_UIDIR)" ]; then \ - echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_UIDIR)" ;\ - $(INSTALL_DIRS) "$(install_prefix)$(GTK_UIDIR)" ;\ - fi ;\ - for target in $(GTK_ICONS) ; do \ - dest=`echo $$target | sed 's@^.*/@@'` ;\ - echo $(INSTALL_DATA) $$target \ - $(install_prefix)$(GTK_UIDIR)/$$dest ;\ - $(INSTALL_DATA) $$target \ - $(install_prefix)$(GTK_UIDIR)/$$dest ;\ - done ;\ - fi - -# xscreensaver.ui -# into /usr/share/xscreensaver/ui/ -install-gnome:: xscreensaver.ui - @if [ "$(GTK_DATADIR)" != "" ]; then \ - if [ ! -d "$(install_prefix)$(GTK_UIDIR)" ]; then \ - echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_UIDIR)" ;\ - $(INSTALL_DIRS) "$(install_prefix)$(GTK_UIDIR)" ;\ - fi ;\ - target=xscreensaver.ui ;\ - echo $(INSTALL_DATA) $(srcdir)/$$target \ - $(install_prefix)$(GTK_UIDIR)/$$target ;\ - if $(INSTALL_DATA) $(srcdir)/$$target \ - $(install_prefix)$(GTK_UIDIR)/$$target ;\ - then true ;\ - else \ - e=echo ; \ - $$e "" ;\ - $$e " ####################################################################";\ - $$e " Warning: unable to install $$target into" ;\ - $$e " $(install_prefix)$(GTK_UIDIR)/." ;\ - $$e " Without this file, xscreensaver-settings will not" ;\ - $$e " be able to run properly." ;\ - $$e " ####################################################################";\ - $$e "" ;\ - exit 1 ; \ - fi ; \ - fi - install-gnome:: uninstall-old-gnome-icons - -update-icon-caches $(install_prefix)$(GTK_DATADIR)/icons - -update-icon-caches $(install_prefix)$(GTK_ICONDIR) -# -update-icon-caches $(install_prefix)$(GTK_DATADIR)/pixmaps +install-gnome:: update-icon-caches + +update-icon-caches:: + @for f in /usr/share/icons/index.theme \ + /usr/share/icons/*/index.theme \ + /usr/share/pixmaps/index.theme \ + /usr/share/pixmaps/*/index.theme \ + ; do \ + if [ -f $$f ]; then \ + f=`dirname $$f` ;\ + echo $(UPDATE_ICON_CACHE) --force --quiet $$f ;\ + $(UPDATE_ICON_CACHE) --force --quiet $$f ;\ + fi ;\ + done # xscreensaver.desktop # xscreensaver-settings.desktop @@ -620,14 +589,14 @@ uninstall-gnome:: echo rm -f $(install_prefix)$(GTK_APPDIR)/$$old ;\ rm -f $(install_prefix)$(GTK_APPDIR)/$$old ;\ fi ;\ - for f in xscreensaver.desktop xscreensaver-settings.desktop; do ;\ + for f in xscreensaver.desktop xscreensaver-settings.desktop; do \ echo rm -f $(install_prefix)$(GTK_APPDIR)/$$f ;\ rm -f $(install_prefix)$(GTK_APPDIR)/$$f ;\ done ;\ fi -# xscreensaver.xpm -# into /usr/share/pixmaps/ +# xscreensaver.xpm (pre-2022) +# from /usr/share/pixmaps/ uninstall-gnome:: @if [ "$(GTK_ICONDIR)" != "" ]; then \ target=xscreensaver.xpm ;\ @@ -635,16 +604,12 @@ uninstall-gnome:: rm -f $(install_prefix)$(GTK_ICONDIR)/$$target ;\ fi -# ../utils/images/screensaver-*.png -# into /usr/share/xscreensaver/ui/ +# /usr/share/xscreensaver/ui/*.png and *.ui no longer used as of 2022, 6.05. uninstall-gnome:: - @if [ "$(GTK_DATADIR)" != "" ]; then \ - for target in $(GTK_ICONS) ; do \ - dest=`echo $$target | sed 's@^.*/@@'` ;\ - echo rm -f $(install_prefix)$(GTK_UIDIR)/$$dest ;\ - rm -f $(install_prefix)$(GTK_UIDIR)/$$dest ;\ - done ;\ - fi + @if [ "$(GTK_ICONDIR)" != "" ]; then \ + echo rm -rf $(install_prefix)$(GTK_SHAREDIR)/ui ;\ + rm -rf $(install_prefix)$(GTK_SHAREDIR)/ui ;\ + fi # What is all this crap with the wrong logo? # /usr/share/icons/nuoveXT2/16x16/apps/xscreensaver.png through @@ -663,20 +628,7 @@ uninstall-old-gnome-icons:: fi ;\ done -# xscreensaver.ui -# into /usr/share/xscreensaver/ui/ -uninstall-gnome:: - @if [ "$(GTK_DATADIR)" != "" ]; then \ - for target in xscreensaver.ui xscreensaver-demo.ui ; do \ - echo rm -f $(install_prefix)$(GTK_UIDIR)/$$target ;\ - rm -f $(install_prefix)$(GTK_UIDIR)/$$target ;\ - done ;\ - rmdir "$(GTK_UIDIR)" ;\ - rmdir "$(GTK_DATADIR)/xscreensaver" ;\ - exit 0 ;\ - fi - -# /usr/share/xscreensaver/glade/ no longer used +# /usr/share/xscreensaver/glade/ no longer used as of 2022. uninstall-gnome:: -rm -rf $(GTK_DATADIR)/xscreensaver/glade @@ -907,6 +859,14 @@ demo-Gtk.o: demo-Gtk.c demo-Gtk-conf.o: demo-Gtk-conf.c $(CC) -c $(CC_ALL) $(GTK_DEFS) $< +GCRARGS = --sourcedir=$(srcdir) --sourcedir=$(ICON_SRC) --generate-source +demo-Gtk-resources.c: gresource.xml demo.ui prefs.ui + $(GLIB_COMPILE_RESOURCES) gresource.xml --target=$@ $(GCRARGS) + +GTK_WARNINGS = -Wno-long-long -Wno-c99-extensions -Wno-pedantic +demo-Gtk-resources.o: demo-Gtk-resources.c + $(CC) -c $(CC_ALL) $(GTK_DEFS) $(GTK_WARNINGS) $< + xscreensaver-settings-Gtk: $(GTK_OBJS) $(CC) $(LDFLAGS) -o $@ $(GTK_OBJS) $(GTK_LIBS) diff --git a/driver/XScreenSaver_ad.h b/driver/XScreenSaver_ad.h index b726096d..8499204c 100644 --- a/driver/XScreenSaver_ad.h +++ b/driver/XScreenSaver_ad.h @@ -36,9 +36,10 @@ "*textURL: https://en.wikipedia.org/w/index.php?title=Special:NewPages&feed=rss", "*demoCommand: xscreensaver-settings", "*helpURL: https://www.jwz.org/xscreensaver/man.html", -"*loadURL: x-www-browser '%s' || firefox '%s' || chromium-browser '%s'", -"*manualCommand: xterm -sb -fg black -bg gray75 -T '%s manual' \ - -e /bin/sh -c 'man \"%s\" ; read foo'", +"*loadURL: gnome-open '%s'", +"*manualCommand: yelp man:%s || \ + x-terminal-emulator -t '%s manual' \ + -e /bin/sh -c \"man %s; read foo\"", "*dateFormat: %I:%M %p, %a %b %e", "*newLoginCommand: no-such-login-manager", "XScreenSaver.pointerHysteresis: 10", diff --git a/driver/blurb.c b/driver/blurb.c index d732a9b1..ddb8b185 100644 --- a/driver/blurb.c +++ b/driver/blurb.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright © 1991-2021 Jamie Zawinski +/* xscreensaver, Copyright © 1991-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -17,20 +17,29 @@ #include #include +#include const char *progname = ""; int verbose_p = 0; +/* #define BLURB_CENTISECONDS */ + const char * blurb (void) { static char buf[255] = { 0 }; struct tm tm; - time_t now; + struct timeval now; int i; - now = time ((time_t *) 0); - localtime_r (&now, &tm); +# ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tzp; + gettimeofday (&now, &tzp); +# else + gettimeofday (&now); +# endif + + localtime_r (&now.tv_sec, &tm); i = strlen (progname); if (i > 40) i = 40; memcpy (buf, progname, i); @@ -44,6 +53,16 @@ blurb (void) buf[i++] = ':'; buf[i++] = '0' + (tm.tm_sec >= 10 ? tm.tm_sec/10 : 0); buf[i++] = '0' + (tm.tm_sec % 10); + +# ifdef BLURB_CENTISECONDS + { + int c = now.tv_usec / 10000; + buf[i++] = '.'; + buf[i++] = '0' + (c >= 10 ? c/10 : 0); + buf[i++] = '0' + (c % 10); + } +# endif + buf[i] = 0; return buf; } diff --git a/driver/clientmsg.c b/driver/clientmsg.c index f407590b..ebfd12da 100644 --- a/driver/clientmsg.c +++ b/driver/clientmsg.c @@ -37,7 +37,7 @@ Window find_screensaver_window (Display *dpy, char **version) { int nscreens = ScreenCount (dpy); - int i, screen; + int screen; Window ret = 0; XErrorHandler old_handler; @@ -51,6 +51,7 @@ find_screensaver_window (Display *dpy, char **version) Window root = RootWindow (dpy, screen); Window root2, parent, *kids; unsigned int nkids; + int i = 0; if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids)) abort (); diff --git a/driver/demo-Gtk-conf.c b/driver/demo-Gtk-conf.c index f7d52031..c9cd2ab3 100644 --- a/driver/demo-Gtk-conf.c +++ b/driver/demo-Gtk-conf.c @@ -46,6 +46,7 @@ # pragma GCC diagnostic pop #endif +#include "blurb.h" #include "demo-Gtk-conf.h" /* Deal with deprecation of direct access to struct fields on the way to GTK3 @@ -64,12 +65,7 @@ #endif -extern const char *blurb (void); - - -const char *hack_configuration_path = HACK_CONFIGURATION_PATH; - -static gboolean debug_p = FALSE; +static gboolean debug_p = FALSE; /* Copied from s->debug_p in parent */ #define MIN_SLIDER_WIDTH 150 @@ -139,7 +135,9 @@ typedef struct { static parameter *make_select_option (const char *file, xmlNodePtr); static void make_parameter_widget (const char *filename, - parameter *, GtkWidget *); + parameter *, GtkWidget *, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data); static void browse_button_cb (GtkButton *button, gpointer user_data); @@ -586,7 +584,6 @@ sanity_check_menu_options (const char *filename, const xmlChar *node_name, int nulls = 0; char *prefix = 0; -/* fprintf (stderr, "\n## %s\n", p->id);*/ for (opts = p->options; opts; opts = opts->next) { parameter *s = (parameter *) opts->data; @@ -700,7 +697,9 @@ sanity_check_parameters (const char *filename, GList *parms) /* Helper for make_parameters() */ static GList * -make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent) +make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data) { GList *list = 0; @@ -710,14 +709,16 @@ make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent) if (!strcmp (name, "hgroup") || !strcmp (name, "vgroup")) { - GtkWidget *box = (*name == 'h' - ? gtk_hbox_new (FALSE, 0) - : gtk_vbox_new (FALSE, 0)); + GtkWidget *box = gtk_box_new (*name == 'h' + ? GTK_ORIENTATION_HORIZONTAL + : GTK_ORIENTATION_VERTICAL, + 0); GList *list2; gtk_widget_show (box); gtk_box_pack_start (GTK_BOX (parent), box, FALSE, FALSE, 0); - list2 = make_parameters_1 (filename, node->xmlChildrenNode, box); + list2 = make_parameters_1 (filename, node->xmlChildrenNode, box, + changed_cb, changed_data); if (list2) list = g_list_concat (list, list2); } @@ -727,7 +728,8 @@ make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent) if (p) { list = g_list_append (list, p); - make_parameter_widget (filename, p, parent); + make_parameter_widget (filename, p, parent, + changed_cb, changed_data); } } } @@ -740,13 +742,16 @@ make_parameters_1 (const char *filename, xmlNodePtr node, GtkWidget *parent) Returns a GList of `parameter' objects. */ static GList * -make_parameters (const char *filename, xmlNodePtr node, GtkWidget *parent) +make_parameters (const char *filename, xmlNodePtr node, GtkWidget *parent, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data) { for (; node; node = node->next) { if (node->type == XML_ELEMENT_NODE && !strcmp ((char *) node->name, "screensaver")) - return make_parameters_1 (filename, node->xmlChildrenNode, parent); + return make_parameters_1 (filename, node->xmlChildrenNode, parent, + changed_cb, changed_data); } return 0; } @@ -843,9 +848,9 @@ make_adjustment (const char *filename, parameter *p) static void set_widget_min_width (GtkWidget *w, int width) { - GtkRequisition req; - gtk_widget_size_request (GTK_WIDGET (w), &req); - if (req.width < width) + GtkRequisition min, nat; + gtk_widget_get_preferred_size (w, &min, &nat); + if (min.width < width) gtk_widget_set_size_request (GTK_WIDGET (w), width, -1); } @@ -857,9 +862,10 @@ set_widget_min_width (GtkWidget *w, int width) static GtkWidget * insert_fake_hbox (GtkWidget *parent) { - if (GTK_IS_VBOX (parent)) + if (gtk_orientable_get_orientation (GTK_ORIENTABLE (parent)) == + GTK_ORIENTATION_VERTICAL) { - GtkWidget *hbox = gtk_hbox_new (FALSE, 0); + GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 4); gtk_widget_show (hbox); return hbox; @@ -869,15 +875,15 @@ insert_fake_hbox (GtkWidget *parent) static void -link_atk_label_to_widget(GtkWidget *label, GtkWidget *widget) +link_atk_label_to_widget (GtkWidget *label, GtkWidget *widget) { - AtkObject *atk_label = gtk_widget_get_accessible (label); - AtkObject *atk_widget = gtk_widget_get_accessible (widget); + AtkObject *atk_label = gtk_widget_get_accessible (label); + AtkObject *atk_widget = gtk_widget_get_accessible (widget); - atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, - atk_widget); - atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, - atk_label); + atk_object_add_relationship (atk_label, ATK_RELATION_LABEL_FOR, + atk_widget); + atk_object_add_relationship (atk_widget, ATK_RELATION_LABELLED_BY, + atk_label); } /* Given a `parameter' struct, allocates an appropriate GtkWidget for it, @@ -885,7 +891,9 @@ link_atk_label_to_widget(GtkWidget *label, GtkWidget *widget) `parent' must be a GtkBox. */ static void -make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) +make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent, + void (*changed_cb) (GtkWidget *, gpointer data), + gpointer changed_data) { const char *label = (char *) p->label; if (p->widget) return; @@ -901,7 +909,8 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) GtkWidget *w = gtk_label_new (_(label)); link_atk_label_to_widget (w, entry); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (w), 1.0); + gtk_label_set_yalign (GTK_LABEL (w), 0.5); set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); @@ -911,6 +920,8 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) if (p->string) gtk_entry_set_text (GTK_ENTRY (p->widget), (char *) p->string); gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); + g_signal_connect (p->widget, "changed", G_CALLBACK (changed_cb), + changed_data); break; } case FILENAME: @@ -923,12 +934,12 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) gtk_widget_show (button); p->widget = entry; - gtk_signal_connect (GTK_OBJECT (button), - "clicked", GTK_SIGNAL_FUNC (browse_button_cb), - (gpointer) entry); + g_signal_connect (button, "clicked", G_CALLBACK (browse_button_cb), + (gpointer) entry); gtk_label_set_justify (GTK_LABEL (L), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (L), 1.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (L), 1.0); + gtk_label_set_yalign (GTK_LABEL (L), 0.5); set_widget_min_width (GTK_WIDGET (L), MIN_LABEL_WIDTH); gtk_widget_show (L); @@ -939,12 +950,14 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) gtk_box_pack_start (GTK_BOX (parent), L, FALSE, FALSE, 4); gtk_box_pack_start (GTK_BOX (parent), entry, TRUE, TRUE, 4); gtk_box_pack_start (GTK_BOX (parent), button, FALSE, FALSE, 4); + g_signal_connect (p->widget, "changed", + G_CALLBACK (changed_cb), changed_data); break; } case SLIDER: { GtkAdjustment *adj = make_adjustment (filename, p); - GtkWidget *scale = gtk_hscale_new (adj); + GtkWidget *scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj); GtkWidget *labelw = 0; if (label) @@ -952,7 +965,8 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) labelw = gtk_label_new (_(label)); link_atk_label_to_widget (labelw, scale); gtk_label_set_justify (GTK_LABEL (labelw), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (labelw), 0.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (labelw), 0.0); + gtk_label_set_yalign (GTK_LABEL (labelw), 0.5); set_widget_min_width (GTK_WIDGET (labelw), MIN_LABEL_WIDTH); gtk_widget_show (labelw); gtk_box_pack_start (GTK_BOX (parent), labelw, FALSE, FALSE, 2); @@ -966,18 +980,21 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) GtkWidget *w = gtk_label_new (_((char *) p->low_label)); link_atk_label_to_widget (w, scale); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (w), 1.0); + gtk_label_set_yalign (GTK_LABEL (w), 0.5); set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_BOTTOM); - /* This is only in debug mode since it is wrong for "ratio" sliders. */ - gtk_scale_set_draw_value (GTK_SCALE (scale), debug_p); gtk_scale_set_digits (GTK_SCALE (scale), (p->integer_p ? 0 : 2)); set_widget_min_width (GTK_WIDGET (scale), MIN_SLIDER_WIDTH); + /* We can't show the value as it is wrong for ratio and inverted + sliders. */ + gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); + gtk_box_pack_start (GTK_BOX (parent), scale, FALSE, FALSE, 4); gtk_widget_show (scale); @@ -987,13 +1004,16 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) GtkWidget *w = gtk_label_new (_((char *) p->high_label)); link_atk_label_to_widget (w, scale); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (w), 0.0); + gtk_label_set_yalign (GTK_LABEL (w), 0.5); set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); gtk_box_pack_start (GTK_BOX (parent), w, FALSE, FALSE, 4); } p->widget = scale; + g_signal_connect (adj, "value-changed", + G_CALLBACK (changed_cb), changed_data); break; } case SPINBUTTON: @@ -1010,7 +1030,8 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) GtkWidget *w = gtk_label_new (_(label)); link_atk_label_to_widget (w, spin); gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5); + gtk_label_set_xalign (GTK_LABEL (w), 1.0); + gtk_label_set_yalign (GTK_LABEL (w), 0.5); set_widget_min_width (GTK_WIDGET (w), MIN_LABEL_WIDTH); gtk_widget_show (w); parent = insert_fake_hbox (parent); @@ -1021,6 +1042,8 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) gtk_box_pack_start (GTK_BOX (parent), spin, FALSE, FALSE, 4); p->widget = spin; + g_signal_connect (adj, "value-changed", + G_CALLBACK (changed_cb), changed_data); break; } case BOOLEAN: @@ -1030,26 +1053,37 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) parent = insert_fake_hbox (parent); */ gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); + g_signal_connect (p->widget, "clicked", + G_CALLBACK (changed_cb), changed_data); break; } case SELECT: { - GtkWidget *opt = gtk_option_menu_new (); - GtkWidget *menu = gtk_menu_new (); + GtkComboBox *cbox = GTK_COMBO_BOX (gtk_combo_box_new()); + GtkListStore *model = gtk_list_store_new (1, G_TYPE_STRING); + GtkCellRenderer *view = gtk_cell_renderer_text_new(); + GtkTreeIter iter; GList *opts; + g_object_set (G_OBJECT (cbox), "model", model, NULL); + g_object_unref (model); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), view, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), view, + "text", 0, NULL); + for (opts = p->options; opts; opts = opts->next) { parameter *s = (parameter *) opts->data; - GtkWidget *i = gtk_menu_item_new_with_label (_((char *) s->label)); - gtk_widget_show (i); - gtk_menu_append (GTK_MENU (menu), i); + const char *name = _((char *) s->label); + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, name, -1); } - gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu); - p->widget = opt; + p->widget = GTK_WIDGET (cbox); parent = insert_fake_hbox (parent); gtk_box_pack_start (GTK_BOX (parent), p->widget, FALSE, FALSE, 4); + g_signal_connect (p->widget, "changed", + G_CALLBACK (changed_cb), changed_data); break; } @@ -1069,76 +1103,28 @@ make_parameter_widget (const char *filename, parameter *p, GtkWidget *parent) } } - -/* File selection. - Absurdly, there is no GTK file entry widget, only a GNOME one, - so in order to avoid depending on GNOME in this code, we have - to do it ourselves. - */ - -/* cancel button on GtkFileSelection: user_data unused */ -static void -file_sel_cancel (GtkWidget *button, gpointer user_data) -{ - GtkWidget *dialog = button; - while (GET_PARENT (dialog)) - dialog = GET_PARENT (dialog); - gtk_widget_destroy (dialog); -} - -/* ok button on GtkFileSelection: user_data is the corresponding GtkEntry */ -static void -file_sel_ok (GtkWidget *button, gpointer user_data) -{ - GtkWidget *entry = GTK_WIDGET (user_data); - GtkWidget *dialog = button; - const char *path; - - while (GET_PARENT (dialog)) - dialog = GET_PARENT (dialog); - gtk_widget_hide (dialog); - - path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (dialog)); - /* apparently one doesn't free `path' */ - - gtk_entry_set_text (GTK_ENTRY (entry), path); - gtk_entry_set_position (GTK_ENTRY (entry), strlen (path)); - - gtk_widget_destroy (dialog); -} - -/* WM close on GtkFileSelection: user_data unused */ -static void -file_sel_close (GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - file_sel_cancel (widget, user_data); -} /* "Browse" button: user_data is the corresponding GtkEntry */ static void browse_button_cb (GtkButton *button, gpointer user_data) { - GtkWidget *entry = GTK_WIDGET (user_data); - const char *text = gtk_entry_get_text (GTK_ENTRY (entry)); - GtkFileSelection *selector = - GTK_FILE_SELECTION (gtk_file_selection_new (_("Select file."))); - - gtk_file_selection_set_filename (selector, text); - gtk_signal_connect (GTK_OBJECT (selector->ok_button), - "clicked", GTK_SIGNAL_FUNC (file_sel_ok), - (gpointer) entry); - gtk_signal_connect (GTK_OBJECT (selector->cancel_button), - "clicked", GTK_SIGNAL_FUNC (file_sel_cancel), - (gpointer) entry); - gtk_signal_connect (GTK_OBJECT (selector), "delete_event", - GTK_SIGNAL_FUNC (file_sel_close), - (gpointer) entry); - - gtk_window_set_modal (GTK_WINDOW (selector), TRUE); - gtk_widget_show (GTK_WIDGET (selector)); + GtkEntry *entry = GTK_ENTRY (user_data); + GtkWindow *win = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))); + const char *ofile = gtk_entry_get_text (entry); + char *file = strdup (ofile); + + if (debug_p) fprintf (stderr, "%s: settings browse button\n", blurb()); + if (file_chooser (win, entry, &file, _("Select file."), + debug_p, FALSE, FALSE)) + { + if (debug_p) + fprintf (stderr, "%s: file: \"%s\" -> \"%s\n", blurb(), ofile, file); + gtk_entry_set_text (entry, file); + } + free (file); } - + /* Converting to and from command-lines */ @@ -1341,21 +1327,19 @@ parameter_to_switch (parameter *p) case SELECT: if (!p->widget) return 0; { - GtkOptionMenu *opt = GTK_OPTION_MENU (p->widget); - GtkMenu *menu = GTK_MENU (gtk_option_menu_get_menu (opt)); - GtkWidget *selected = gtk_menu_get_active (menu); - GList *kids = gtk_container_children (GTK_CONTAINER (menu)); - int menu_elt = g_list_index (kids, (gpointer) selected); - GList *ol = g_list_nth (p->options, menu_elt); + GtkComboBox *cbox = GTK_COMBO_BOX (p->widget); + int menu_elt = gtk_combo_box_get_active (cbox); + GList *ol = (menu_elt >= 0 ? g_list_nth (p->options, menu_elt) : NULL); parameter *o = (ol ? (parameter *) ol->data : 0); const char *s; - if (!o) abort(); - if (o->type != SELECT_OPTION) abort(); - s = (char *) o->arg_set; - if (s) - return strdup (s); - else - return 0; + if (o) + { + if (o->type != SELECT_OPTION) abort(); + s = (char *) o->arg_set; + if (s) + return strdup (s); + } + return 0; } default: if (p->widget) @@ -1494,10 +1478,12 @@ parse_command_line_into_parameters (const char *filename, if (rest->next) /* pop off the arg to this option */ { char *s = (char *) rest->next->data; - /* the next token is the next switch iff it matches "-[a-z]". + /* the next token is the next switch if it matches ^-[-a-z] (To avoid losing on "-x -3.1".) */ - if (s && (s[0] != '-' || !isalpha(s[1]))) + if (! (s && + s[0] == '-' && + (s[1] == '-' || isalpha(s[1])))) { value = s; rest->next->data = 0; @@ -1519,9 +1505,14 @@ static gboolean compare_opts (const char *option, const char *value, const char *template) { - int ol = strlen (option); + int ol; char *c; + /* -arg and --arg are the same. */ + if (option[0] == '-' && option[1] == '-') option++; + if (template[0] == '-' && template[1] == '-') template++; + ol = strlen (option); + if (strncmp (option, template, ol)) return FALSE; @@ -1686,8 +1677,8 @@ parameter_set_switch (parameter *p, gpointer value) } case SELECT: { - gtk_option_menu_set_history (GTK_OPTION_MENU (p->widget), - GPOINTER_TO_INT(value)); + GtkComboBox *cbox = GTK_COMBO_BOX (p->widget); + gtk_combo_box_set_active (cbox, GPOINTER_TO_INT(value)); break; } default: @@ -1752,7 +1743,7 @@ restore_defaults (const char *progname, GList *parms) } case SELECT: { - GtkOptionMenu *opt = GTK_OPTION_MENU (p->widget); + GtkComboBox *cbox = GTK_COMBO_BOX (p->widget); GList *opts; int selected = 0; int index; @@ -1770,7 +1761,7 @@ restore_defaults (const char *progname, GList *parms) } } - gtk_option_menu_set_history (GTK_OPTION_MENU (opt), selected); + gtk_combo_box_set_active (cbox, selected); break; } default: @@ -1780,7 +1771,7 @@ restore_defaults (const char *progname, GList *parms) } - + /* Documentation strings */ @@ -1890,15 +1881,17 @@ get_year (const char *desc) } - + /* External interface. */ static conf_data * load_configurator_1 (const char *program, const char *arguments, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data, gboolean verbose_p) { - const char *dir = hack_configuration_path; + const char *dir = HACK_CONFIGURATION_PATH; char *base_program; int L = strlen (dir); char *file; @@ -1959,10 +1952,11 @@ load_configurator_1 (const char *program, const char *arguments, /* Parsed the XML file. Now make some widgets. */ - vbox0 = gtk_vbox_new (FALSE, 0); + vbox0 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show (vbox0); - parms = make_parameters (file, doc->xmlRootNode, vbox0); + parms = make_parameters (file, doc->xmlRootNode, vbox0, + changed_cb, changed_data); sanity_check_parameters (file, parms); xmlFreeDoc (doc); @@ -2034,14 +2028,17 @@ split_command_line (const char *full_command_line, conf_data * -load_configurator (const char *full_command_line, gboolean verbose_p) +load_configurator (const char *full_command_line, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data, + gboolean verbose_p) { char *prog; char *args; conf_data *cd; debug_p = verbose_p; split_command_line (full_command_line, &prog, &args); - cd = load_configurator_1 (prog, args, verbose_p); + cd = load_configurator_1 (prog, args, changed_cb, changed_data, verbose_p); free (prog); free (args); return cd; diff --git a/driver/demo-Gtk-conf.h b/driver/demo-Gtk-conf.h index 2a660f68..31f7ed8d 100644 --- a/driver/demo-Gtk-conf.h +++ b/driver/demo-Gtk-conf.h @@ -22,11 +22,56 @@ typedef struct { int year; } conf_data; -extern conf_data *load_configurator (const char *cmd_line, gboolean verbose_p); +/* Referenced by demo-Gtk.c; defined in demo-Gtk-conf.c. + */ +extern conf_data *load_configurator (const char *cmd_line, + void (*changed_cb) (GtkWidget *, gpointer), + gpointer changed_data, + gboolean verbose_p); extern char *get_configurator_command_line (conf_data *, gboolean default_p); extern void set_configurator_command_line (conf_data *, const char *cmd_line); extern void free_conf_data (conf_data *); -extern const char *hack_configuration_path; +/* Referenced from demo.ui and prefs.ui; defined in demo-Gtk.c. + */ +extern void quit_menu_cb (GtkAction *, gpointer user_data); +extern void about_menu_cb (GtkAction *, gpointer user_data); +extern void doc_menu_cb (GtkAction *, gpointer user_data); +extern void file_menu_cb (GtkAction *, gpointer user_data); +extern void activate_menu_cb (GtkAction *, gpointer user_data); +extern void lock_menu_cb (GtkAction *, gpointer user_data); +extern void kill_menu_cb (GtkAction *, gpointer user_data); +extern void restart_menu_cb (GtkWidget *, gpointer user_data); +extern void run_this_cb (GtkButton *, gpointer user_data); +extern void manual_cb (GtkButton *, gpointer user_data); +extern void run_next_cb (GtkButton *, gpointer user_data); +extern void run_prev_cb (GtkButton *, gpointer user_data); +extern gboolean pref_changed_cb (GtkWidget *, gpointer user_data); +extern gboolean pref_changed_event_cb (GtkWidget *, GdkEvent *, gpointer data); +extern gboolean image_text_pref_changed_event_cb (GtkWidget *, GdkEvent *, + gpointer user_data); +extern void mode_menu_item_cb (GtkWidget *, gpointer user_data); +extern void switch_page_cb (GtkNotebook *, GtkWidget *, + gint page_num, gpointer user_data); +extern void browse_image_dir_cb (GtkButton *, gpointer user_data); +extern void browse_text_file_cb (GtkButton *, gpointer user_data); +extern void browse_text_program_cb (GtkButton *, gpointer user_data); +extern void settings_cb (GtkButton *, gpointer user_data); +extern void settings_adv_cb (GtkButton *, gpointer user_data); +extern void settings_std_cb (GtkButton *, gpointer user_data); +extern void settings_reset_cb (GtkButton *, gpointer user_data); +extern void settings_switch_page_cb (GtkNotebook *, GtkWidget *, + gint page_num, gpointer user_data); +extern void settings_cancel_cb (GtkWidget *, gpointer user_data); +extern void settings_ok_cb (GtkWidget *, gpointer user_data); +extern void preview_theme_cb (GtkWidget *, gpointer user_data); + +/* Referenced by demo-Gtk-conf.c; defined in demo-Gtk.c. + */ +extern void warning_dialog (GtkWindow *, const char *title, const char *msg); +extern gboolean file_chooser (GtkWindow *, GtkEntry *, char **retP, + const char *title, + gboolean verbose_p, + gboolean dir_p, gboolean program_p); #endif /* _DEMO_GTK_CONF_H_ */ diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index 0406d313..442dac1a 100644 --- a/driver/demo-Gtk.c +++ b/driver/demo-Gtk.c @@ -16,23 +16,6 @@ #ifdef HAVE_GTK /* whole file */ -#include "blurb.h" - -#include - -#include - -#ifdef HAVE_UNISTD_H -# include -#endif - -# ifdef __GNUC__ -# define STFU __extension__ /* ignore gcc -pendantic warnings in next sexp */ -# else -# define STFU /* */ -# endif - - #ifdef ENABLE_NLS # include #endif /* ENABLE_NLS */ @@ -42,32 +25,22 @@ #endif /* HAVE_UNAME */ #include +#include +#include +#include #include #include /* for getpwuid() */ #include #include - #include #include #ifdef HAVE_SYS_WAIT_H # include /* for waitpid() and associated macros */ #endif - -#include /* for CARD32 */ #include /* for XA_INTEGER */ -#include -#include - -/* We don't actually use any widget internals, but these are included - so that gdb will have debug info for the widgets... */ -#include -#include - -#ifdef HAVE_XINERAMA -# include -#endif /* HAVE_XINERAMA */ +#include #if (__GNUC__ >= 4) /* Ignore useless warnings generated by gtk.h */ # undef inline @@ -80,20 +53,14 @@ #endif #include - -#include - -#ifndef HAVE_GTK2 -# error GTK 2.x is required -#endif - -#include +#include /* For gdk_x11_get_default_xdisplay(), etc. */ #if (__GNUC__ >= 4) # pragma GCC diagnostic pop #endif - +#include "blurb.h" +#include "xscreensaver-intl.h" #include "version.h" #include "types.h" #include "resources.h" /* for parse_time() */ @@ -102,87 +69,48 @@ #include "visual.h" #include "atoms.h" #include "usleep.h" +#include "atoms.h" #include "xmu.h" -#include "logo-50.xpm" -#include "logo-180.xpm" - #include "demo-Gtk-conf.h" -#include "atoms.h" - -#include -#include -#include - -enum { - COL_ENABLED, - COL_NAME, - COL_LAST -}; - -/* Deal with deprecation of direct access to struct fields on the way to GTK3 - See http://live.gnome.org/GnomeGoals/UseGseal - */ -#if GTK_CHECK_VERSION(2,14,0) -# define GET_PARENT(w) gtk_widget_get_parent (w) -# define GET_WINDOW(w) gtk_widget_get_window (w) -# define GET_ACTION_AREA(d) gtk_dialog_get_action_area (d) -# define GET_CONTENT_AREA(d) gtk_dialog_get_content_area (d) -# define GET_ADJ_VALUE(a) gtk_adjustment_get_value (a) -# define SET_ADJ_VALUE(a,v) gtk_adjustment_set_value (a, v) -# define SET_ADJ_UPPER(a,v) gtk_adjustment_set_upper (a, v) -#else -# define GET_PARENT(w) ((w)->parent) -# define GET_WINDOW(w) ((w)->window) -# define GET_ACTION_AREA(d) ((d)->action_area) -# define GET_CONTENT_AREA(d) ((d)->vbox) -# define GET_ADJ_VALUE(a) ((a)->value) -# define SET_ADJ_VALUE(a,v) (a)->value = v -# define SET_ADJ_UPPER(a,v) (a)->upper = v -#endif - -#if GTK_CHECK_VERSION(2,18,0) -# define SET_CAN_DEFAULT(w) gtk_widget_set_can_default ((w), TRUE) -# define GET_SENSITIVE(w) gtk_widget_get_sensitive (w) -#else -# define SET_CAN_DEFAULT(w) GTK_WIDGET_SET_FLAGS ((w), GTK_CAN_DEFAULT) -# define GET_SENSITIVE(w) GTK_WIDGET_IS_SENSITIVE (w) -#endif -#if GTK_CHECK_VERSION(2,20,0) -# define GET_REALIZED(w) gtk_widget_get_realized (w) -#else -# define GET_REALIZED(w) GTK_WIDGET_REALIZED (w) -#endif /* from exec.c */ extern void exec_command (const char *shell, const char *command, int nice); extern int on_path_p (const char *program); -static void hack_subproc_environment (Window preview_window_id, Bool debug_p); #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) +const char *progclass = "XScreenSaver"; -char *progclass = "XScreenSaver"; -XrmDatabase db; +#ifdef __GNUC__ +# define STFU __extension__ /* ignore gcc -pendantic warnings in next sexp */ +#endif +static char *defaults[] = { +#include "XScreenSaver_ad.h" + 0 +}; /* The order of the items in the mode menu. */ static int mode_menu_order[] = { DONT_BLANK, BLANK_ONLY, ONE_HACK, RANDOM_HACKS, RANDOM_HACKS_SAME }; +enum { COL_ENABLED, COL_NAME, COL_LAST }; +typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button; typedef struct { char *short_version; /* version number of this xscreensaver build */ - GtkWidget *toplevel_widget; /* the main window */ - GtkWidget *base_widget; /* root of our hierarchy (for name lookups) */ - GtkWidget *popup_widget; /* the "Settings" dialog */ - conf_data *cdata; /* private data for per-hack configuration */ + GtkWindow *window; + GtkWindow *dialog; + + Display *dpy; + Bool wayland_p; - GtkBuilder *gtk_ui; /* UI file */ + conf_data *cdata; /* private data for per-hack configuration */ Bool debug_p; /* whether to print diagnostics */ Bool initializing_p; /* flag for breaking recursion loops */ @@ -216,9 +144,141 @@ typedef struct { } state; -/* Total fucking evilness due to the fact that it's rocket science to get - a closure object of our own down into the various widget callbacks. */ -static state *global_state_kludge; +/* Class definitions for the application and two windows. The classes are: + + XScreenSaverApp -- The invisible GtkApplication main-loop framework. + XScreenSaverWindow -- The main window with the scrolling list of hacks. + XScreenSaverDialog -- The per-hack settings window. + */ +#define XSCREENSAVER_APP_TYPE (xscreensaver_app_get_type()) +G_DECLARE_FINAL_TYPE (XScreenSaverApp, xscreensaver_app, XSCREENSAVER, APP, + GtkApplication) + +struct _XScreenSaverApp { + GtkApplication parent; + Bool cmdline_debug_p; +}; + + +G_DEFINE_TYPE (XScreenSaverApp, xscreensaver_app, GTK_TYPE_APPLICATION) + +/* The widgets we reference from the demo.ui file. + */ +#define ALL_WINDOW_WIDGETS \ + W(activate_menuitem) \ + W(lock_menuitem) \ + W(kill_menuitem) \ + W(list) \ + W(scroller) \ + W(preview_frame) \ + W(short_preview_label) \ + W(preview_author_label) \ + W(timeout_spinbutton) \ + W(cycle_spinbutton) \ + W(lock_spinbutton) \ + W(dpms_standby_spinbutton) \ + W(dpms_suspend_spinbutton) \ + W(dpms_off_spinbutton) \ + W(fade_spinbutton) \ + W(lock_button) \ + W(dpms_button) \ + W(dpms_quickoff_button) \ + W(grab_desk_button) \ + W(grab_video_button) \ + W(grab_image_button) \ + W(fade_button) \ + W(unfade_button) \ + W(preview) \ + W(preview_notebook) \ + W(text_radio) \ + W(text_file_radio) \ + W(text_file_browse) \ + W(text_program_radio) \ + W(text_url_radio) \ + W(text_host_radio) \ + W(image_text) \ + W(image_browse_button) \ + W(text_entry) \ + W(text_file_entry) \ + W(text_program_entry) \ + W(text_url_entry) \ + W(text_program_browse) \ + W(theme_menu) \ + W(mode_menu) \ + W(next_prev_hbox) \ + W(blanking_table) \ + W(lock_mlabel) \ + W(dpms_frame) \ + W(dpms_standby_label) \ + W(dpms_standby_mlabel) \ + W(dpms_suspend_label) \ + W(dpms_suspend_mlabel) \ + W(dpms_off_label) \ + W(dpms_off_mlabel) \ + W(fade_label) \ + W(demo) \ + W(settings) \ + +/* The widgets we reference from the prefs.ui file. + */ +#define ALL_DIALOG_WIDGETS \ + W(opt_notebook) \ + W(doc) \ + W(settings_vbox) \ + W(cmd_text) \ + W(opt_frame) \ + W(dialog_vbox) \ + W(adv_button) \ + W(std_button) \ + W(cmd_label) \ + W(manual) \ + W(visual) \ + W(visual_combo) \ + W(reset_button) \ + W(ok_button) \ + +#define XSCREENSAVER_WINDOW_TYPE (xscreensaver_window_get_type()) +G_DECLARE_FINAL_TYPE (XScreenSaverWindow, xscreensaver_window, + XSCREENSAVER, WINDOW, GtkApplicationWindow) + +struct _XScreenSaverWindow { + GtkApplicationWindow parent; + state state; + + GtkWidget +# undef W +# define W(NAME) * NAME, + ALL_WINDOW_WIDGETS + *_dummy; +# undef W +}; + +G_DEFINE_TYPE (XScreenSaverWindow, xscreensaver_window, + GTK_TYPE_APPLICATION_WINDOW) + + +#define XSCREENSAVER_DIALOG_TYPE (xscreensaver_dialog_get_type()) +G_DECLARE_FINAL_TYPE (XScreenSaverDialog, xscreensaver_dialog, + XSCREENSAVER, DIALOG, GtkDialog) + +struct _XScreenSaverDialog { + GtkApplicationWindow parent; + XScreenSaverWindow *main; + char *unedited_cmdline; /* Current hack command line before saving */ + + GtkWidget +# undef W +# define W(NAME) * NAME, + ALL_DIALOG_WIDGETS + *_dummy; +# undef W +}; + +G_DEFINE_TYPE (XScreenSaverDialog, xscreensaver_dialog, + GTK_TYPE_DIALOG) + + +static void hack_subproc_environment (Window preview_window_id, Bool debug_p); static void populate_demo_window (state *, int list_elt); static void populate_prefs_page (state *); @@ -231,115 +291,244 @@ static int maybe_reload_init_file (state *); static void await_xscreensaver (state *); static Bool xscreensaver_running_p (state *); static void sensitize_menu_items (state *s, Bool force_p); -static void force_dialog_repaint (state *s); static void schedule_preview (state *, const char *cmd); static void kill_preview_subproc (state *, Bool reset_p); static void schedule_preview_check (state *); +static void sensitize_demo_widgets (state *, Bool sensitive_p); +static void kill_gnome_screensaver (state *); +static void kill_kde_screensaver (state *); -/* Prototypes of functions used by the Gtk-generated code, to avoid warnings. +/* Some pathname utilities */ + +/* Removed redundant . and .. components from the pathname. + Strip leading and trailing spaces. + Make it have a trailing slash if it should be a directory. */ -void exit_menu_cb (GtkAction *, gpointer user_data); -void about_menu_cb (GtkAction *, gpointer user_data); -void doc_menu_cb (GtkAction *, gpointer user_data); -void file_menu_cb (GtkAction *, gpointer user_data); -void activate_menu_cb (GtkAction *, gpointer user_data); -void lock_menu_cb (GtkAction *, gpointer user_data); -void kill_menu_cb (GtkAction *, gpointer user_data); -void restart_menu_cb (GtkWidget *, gpointer user_data); -void run_this_cb (GtkButton *, gpointer user_data); -void manual_cb (GtkButton *, gpointer user_data); -void run_next_cb (GtkButton *, gpointer user_data); -void run_prev_cb (GtkButton *, gpointer user_data); -void pref_changed_cb (GtkWidget *, gpointer user_data); -gboolean pref_changed_event_cb (GtkWidget *, GdkEvent *, gpointer user_data); -gboolean image_text_pref_changed_event_cb (GtkWidget *, GdkEvent *, - gpointer user_data); -void mode_menu_item_cb (GtkWidget *, gpointer user_data); -void switch_page_cb (GtkNotebook *, GtkNotebookPage *, - gint page_num, gpointer user_data); -void browse_image_dir_cb (GtkButton *, gpointer user_data); -void browse_text_file_cb (GtkButton *, gpointer user_data); -void browse_text_program_cb (GtkButton *, gpointer user_data); -void settings_cb (GtkButton *, gpointer user_data); -void settings_adv_cb (GtkButton *, gpointer user_data); -void settings_std_cb (GtkButton *, gpointer user_data); -void settings_reset_cb (GtkButton *, gpointer user_data); -void settings_switch_page_cb (GtkNotebook *, GtkNotebookPage *, - gint page_num, gpointer user_data); -void settings_cancel_cb (GtkButton *, gpointer user_data); -void settings_ok_cb (GtkButton *, gpointer user_data); -void preview_theme_cb (GtkWidget *, gpointer user_data); - -static void kill_gnome_screensaver (void); -static void kill_kde_screensaver (void); +static char * +normalize_pathname (const char *path, gboolean dir_p) +{ + int L; + char *p2, *s; + if (!path) return 0; + if (!*path) return strdup (""); -/* Some random utility functions + /* Strip leading spaces */ + while (isspace (*path)) path++; + + L = strlen (path); + p2 = (char *) malloc (L + 3); + strcpy (p2, path); + + /* Strip trailing spaces and slashes */ + while (L > 0 && (isspace (p2[L-1]) || p2[L-1] == '/')) + p2[--L] = 0; + + for (s = p2; s && *s; s++) + { + if (*s == '/' && + (!strncmp (s, "/../", 4) || /* delete "XYZ/../" */ + !strncmp (s, "/..\000", 4))) /* delete "XYZ/..$" */ + { + char *s0 = s; + while (s0 > p2 && s0[-1] != '/') + s0--; + if (s0 > p2) + { + s0--; + s += 3; + /* strcpy (s0, s); */ + memmove(s0, s, strlen(s) + 1); + s = s0-1; + } + } + else if (*s == '/' && !strncmp (s, "/./", 3)) { /* delete "/./" */ + /* strcpy (s, s+2), s--; */ + memmove(s, s+2, strlen(s+2) + 1); + s--; + } + else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */ + *s = 0, s--; + } + + /* + Normalize consecutive slashes. + Ignore doubled slashes after ":" to avoid mangling URLs. + */ + + for (s = p2; s && *s; s++){ + if (*s == ':') continue; + if (!s[1] || !s[2]) continue; + while (s[1] == '/' && s[2] == '/') + /* strcpy (s+1, s+2); */ + memmove (s+1, s+2, strlen(s+2) + 1); + } + + /* and strip trailing whitespace for good measure. */ + L = strlen(p2); + while (isspace(p2[L-1])) + p2[--L] = 0; + + if (dir_p) + { + p2[L++] = '/'; /* Add trailing slash */ + p2[L] = 0; + } + + return p2; +} + + +/* Expand or un-expand ~/ to $HOME in a pathname, as requested. + Strip leading and trailing spaces. + Make it have a trailing slash if it should be a directory. */ +static char * +pathname_tilde (const char *p, gboolean add_p, gboolean dir_p) +{ + char *p2; + if (!p) return 0; + + p2 = normalize_pathname (p, dir_p); + p = p2; + + if (add_p) + { + const char *home = getenv("HOME"); + int L = strlen(home); + if (!strncmp (home, p, L) && p[L] == '/') + { + char *p3 = (char *) malloc (strlen (p) + 4); + strcpy (p3, "~"); + strcat (p3, p + L); + free (p2); + p2 = p3; + } + } + else if (!strncmp (p, "~/", 2)) + { + const char *home = getenv("HOME"); + char *p3 = (char *) malloc (strlen (p) + strlen (home) + 4); + strcpy (p3, home); + strcat (p3, p + 1); + free (p2); + p2 = p3; + } + + return p2; +} + + +/* Is the path a directory that exists? */ +static gboolean +directory_p (const char *path) +{ + char *p2 = pathname_tilde (path, FALSE, FALSE); /* no slash on dir */ + struct stat st; + gboolean ok = FALSE; + + if (!p2 || !*p2) + ok = FALSE; + else if (stat (p2, &st)) + ok = FALSE; + else if (!S_ISDIR (st.st_mode)) + ok = FALSE; + else + ok = TRUE; + free (p2); + return ok; +} + + +/* Is the path a file (not directory) that exists? */ +static gboolean +file_p (const char *path) +{ + char *p2 = pathname_tilde (path, FALSE, FALSE); + struct stat st; + gboolean ok = FALSE; + if (!p2 || !*p2) + ok = FALSE; + else if (stat (p2, &st)) + ok = FALSE; + else if (S_ISDIR (st.st_mode)) + ok = FALSE; + else + ok = TRUE; + free (p2); + return ok; +} + + -static GtkWidget * -name_to_widget (state *s, const char *name) +/* See if the directory has at least one image file under it. + Recurses to at most the given depth, chasing symlinks. + To do this properly would mean running "xscreensaver-getimage-file" + and seeing if it found anything, but that might take a long time to + build the cache the first time, so this is close enough. + */ +static Bool +image_files_p (const char *path, int max_depth) { - GtkWidget *w; - if (!s) abort(); - if (!name) abort(); - if (!*name) abort(); + const char * const exts[] = { + "jpg", "jpeg", "pjpeg", "pjpg", "png", "gif", + "tif", "tiff", "xbm", "xpm", "svg", + }; + struct dirent *de; + Bool ok = FALSE; + char *p2 = pathname_tilde (path, FALSE, FALSE); /* no slash on dir */ + DIR *dir = opendir (p2); + if (!dir) goto DONE; - if (!s->gtk_ui) + while (!ok && (de = readdir (dir))) { - /* First try to load the UI file from the current directory; - if there isn't one there, check the installed directory. - */ -# define UI_FILE "xscreensaver.ui" - const char * const files[] = { UI_FILE, - DEFAULT_ICONDIR "/" UI_FILE }; - int i; + struct stat st; + const char *f = de->d_name; + char *f2; + if (*f == '.') continue; - s->gtk_ui = gtk_builder_new (); + f2 = (char *) malloc (strlen(p2) + strlen(f) + 10); + strcpy (f2, p2); + strcat (f2, "/"); + strcat (f2, f); - for (i = 0; i < countof (files); i++) + if (!stat (f2, &st)) { - struct stat st; - if (!stat (files[i], &st)) + if (S_ISDIR (st.st_mode)) { - GError* error = NULL; - - if (gtk_builder_add_from_file (s->gtk_ui, files[i], &error)) - break; - else - { - g_warning ("Couldn't load builder file %s: %s", - files[i], error->message); - g_error_free (error); - } + if (max_depth > 0 && image_files_p (f2, max_depth - 1)) + ok = TRUE; + } + else + { + int i; + const char *ext = strrchr (f, '.'); + if (ext) + for (i = 0; i < countof(exts); i++) + if (!strcasecmp (ext+1, exts[i])) + { + /* fprintf (stderr, "%s: found %s\n", blurb(), f2); */ + ok = TRUE; + break; + } } } - if (i >= countof (files)) - { - fprintf (stderr, - "%s: could not load \"" UI_FILE "\"\n" - "\tfrom " DEFAULT_ICONDIR "/ or current directory.\n", - blurb()); - exit (-1); - } -# undef UI_FILE - gtk_builder_connect_signals (s->gtk_ui, NULL); + free (f2); } - w = GTK_WIDGET (gtk_builder_get_object (s->gtk_ui, name)); - - if (w) return w; - - fprintf (stderr, "%s: no widget \"%s\" (wrong UI file?)\n", - blurb(), name); - abort(); + closedir (dir); + DONE: + free (p2); + return ok; } -/* Why this behavior isn't automatic in *either* toolkit, I'll never know. - Takes a scroller, viewport, or list as an argument. +/* Some random utility functions + */ + +/* Why this behavior isn't automatic, I'll never understand. */ static void ensure_selected_item_visible (GtkWidget *widget) @@ -351,9 +540,9 @@ ensure_selected_item_visible (GtkWidget *widget) selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) - path = gtk_tree_path_new_first (); + path = gtk_tree_path_new_first (); else - path = gtk_tree_model_get_path (model, &iter); + path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); @@ -361,224 +550,133 @@ ensure_selected_item_visible (GtkWidget *widget) } -/* The "OK" button on a warning dialog. */ static void -warning_dialog_dismiss_cb (GtkWidget *widget, gpointer user_data) +warning_dialog_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { - GtkWidget *shell = GTK_WIDGET (user_data); - while (GET_PARENT (shell)) - shell = GET_PARENT (shell); - gtk_widget_destroy (GTK_WIDGET (shell)); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + switch (response_id) { + case D_LAUNCH: restart_menu_cb (GTK_WIDGET (dialog), user_data); break; + case D_GNOME: kill_gnome_screensaver (s); break; + case D_KDE: kill_kde_screensaver (s); break; + default: /* D_NONE or GTK_RESPONSE_DELETE_EVENT */ + break; + } + gtk_widget_destroy (GTK_WIDGET (dialog)); } -void restart_menu_cb (GtkWidget *widget, gpointer user_data); - -/* The "Restart daemon" button on a warning dialog. */ -static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data) +static Bool +warning_dialog_1 (GtkWindow *win, + const char *title, + const char *message, + dialog_button button_type) { - restart_menu_cb (widget, user_data); - warning_dialog_dismiss_cb (widget, user_data); -} + GtkWidget *dialog = + (button_type == D_NONE + ? gtk_dialog_new_with_buttons (title, win, + GTK_DIALOG_DESTROY_WITH_PARENT, + _("_OK"), D_NONE, + NULL) + : gtk_dialog_new_with_buttons (title, win, + GTK_DIALOG_DESTROY_WITH_PARENT, + (button_type == D_LAUNCH ? _("Launch") : + button_type == D_GNOME ? _("Kill") : + button_type == D_KDE ? _("Kill") : + _("_OK")), + button_type, + _("_Cancel"), D_NONE, + NULL)); + GtkWidget *content_area = + gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + GtkWidget *im = gtk_image_new_from_icon_name ("dialog-warning", + GTK_ICON_SIZE_DIALOG); + GtkWidget *label = gtk_label_new (message); + int margin = 32; + + gtk_box_pack_start (GTK_BOX (hbox), im, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (content_area), hbox); + + gtk_widget_set_margin_start (hbox, margin); + gtk_widget_set_margin_end (hbox, margin); + gtk_widget_set_margin_top (hbox, margin); + gtk_widget_set_margin_bottom (hbox, margin / 2); + + gtk_widget_set_margin_start (label, margin / 2); + gtk_widget_set_valign (im, GTK_ALIGN_START); + + g_signal_connect (dialog, "response", + G_CALLBACK (warning_dialog_cb), + win); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), button_type); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_window_set_transient_for (GTK_WINDOW (dialog), win); + gtk_widget_show_all (dialog); -/* The "Kill gnome-screensaver" button on a warning dialog. */ -static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data) -{ - kill_gnome_screensaver (); - warning_dialog_dismiss_cb (widget, user_data); + return TRUE; } -/* The "Kill kde-screensaver" button on a warning dialog. */ -static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data) + +void +warning_dialog (GtkWindow *win, const char *title, const char *message) { - kill_kde_screensaver (); - warning_dialog_dismiss_cb (widget, user_data); + warning_dialog_1 (win, title, message, D_NONE); } -typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button; -static Bool -warning_dialog (GtkWidget *parent, const char *message, - dialog_button button_type, int center) +static void +run_cmd (state *s, Atom command, int arg) { - char *msg = strdup (message); - char *head; + char *err = 0; + int status; + + if (!s->dpy) return; + flush_dialog_changes_and_save (s); - GtkWidget *dialog = gtk_dialog_new (); - GtkWidget *label = 0; - GtkWidget *ok = 0; - GtkWidget *cancel = 0; - int margin_x = 48; - int margin_y = 4; - int i = 0; + if (s->debug_p) + fprintf (stderr, "%s: command: %s %d\n", blurb(), + XGetAtomName (s->dpy, command), arg); + status = xscreensaver_command (s->dpy, command, arg, FALSE, &err); - while (parent && !GET_WINDOW (parent)) - parent = GET_PARENT (parent); + /* Kludge: ignore the spurious "window unexpectedly deleted" errors... */ + if (status < 0 && err && strstr (err, "unexpectedly deleted")) + status = 0; - if (!parent || - !GET_WINDOW (parent)) /* too early to pop up transient dialogs */ + if (status < 0) { - fprintf (stderr, - "%s: too early for warning dialog?" - "\n\n\t%s\n\n", - progname, message); - free(msg); - return False; + char buf [255]; + sprintf (buf, "%.100s", (err ? err : _("Unknown error!"))); + warning_dialog (s->window, _("Error"), buf); } + if (err) free (err); - /* Top margin */ - label = gtk_label_new (""); - gtk_misc_set_padding (GTK_MISC (label), 0, margin_y); - gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - gtk_widget_show (label); + sensitize_menu_items (s, TRUE); +} - head = msg; - while (head) - { - char name[20]; - char *s = strchr (head, '\n'); - if (s) *s = 0; - sprintf (name, "label%d", i++); +static void +run_hack (state *s, int list_elt, Bool report_errors_p) +{ + int hack_number; + char *err = 0; + int status; - { - label = gtk_label_new (head); - gtk_label_set_selectable (GTK_LABEL (label), TRUE); - gtk_misc_set_padding (GTK_MISC (label), margin_x, 0); - - if (center <= 0) - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - gtk_widget_show (label); - } - - if (s) - head = s+1; - else - head = 0; - - center--; - } - - /* Bottom margin */ - label = gtk_label_new (""); - gtk_misc_set_padding (GTK_MISC (label), 0, margin_y * 2); - gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - gtk_widget_show (label); - - label = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - - if (button_type != D_NONE) - { - cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - gtk_container_add (GTK_CONTAINER (label), cancel); - } - - ok = gtk_button_new_from_stock (GTK_STOCK_OK); - gtk_container_add (GTK_CONTAINER (label), ok); - - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 10); - gtk_window_set_title (GTK_WINDOW (dialog), progclass); - SET_CAN_DEFAULT (ok); - gtk_widget_show (ok); - gtk_widget_grab_focus (ok); - - if (cancel) - { - SET_CAN_DEFAULT (cancel); - gtk_widget_show (cancel); - } - gtk_widget_show (label); - gtk_widget_show (dialog); - - if (button_type != D_NONE) - { - GtkSignalFunc fn; - switch (button_type) { - case D_LAUNCH: fn = GTK_SIGNAL_FUNC (warning_dialog_restart_cb); break; - case D_GNOME: fn = GTK_SIGNAL_FUNC (warning_dialog_killg_cb); break; - case D_KDE: fn = GTK_SIGNAL_FUNC (warning_dialog_killk_cb); break; - default: abort(); break; - } - gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn, - (gpointer) dialog); - gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked", - GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb), - (gpointer) dialog); - } - else - { - gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", - GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb), - (gpointer) dialog); - } - - gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)), - GET_WINDOW (GTK_WIDGET (parent))); - - gtk_window_present (GTK_WINDOW (dialog)); - - free (msg); - return True; -} - - -static void -run_cmd (state *s, Atom command, int arg) -{ - char *err = 0; - int status; - - flush_dialog_changes_and_save (s); - - if (s->debug_p) - fprintf (stderr, "%s: command: %s %d\n", blurb(), - XGetAtomName (GDK_DISPLAY(), command), arg); - status = xscreensaver_command (GDK_DISPLAY(), command, arg, False, &err); - - /* Kludge: ignore the spurious "window unexpectedly deleted" errors... */ - if (status < 0 && err && strstr (err, "unexpectedly deleted")) - status = 0; - - if (status < 0) - { - char buf [255]; - if (err) - sprintf (buf, "Error:\n\n%s", err); - else - strcpy (buf, "Unknown error!"); - warning_dialog (s->toplevel_widget, buf, D_NONE, 100); - } - if (err) free (err); - - sensitize_menu_items (s, True); - force_dialog_repaint (s); -} - - -static void -run_hack (state *s, int list_elt, Bool report_errors_p) -{ - int hack_number; - char *err = 0; - int status; - - if (list_elt < 0) return; - hack_number = s->list_elt_to_hack_number[list_elt]; + if (!s->dpy) return; + if (list_elt < 0) return; + hack_number = s->list_elt_to_hack_number[list_elt]; flush_dialog_changes_and_save (s); schedule_preview (s, 0); if (s->debug_p) fprintf (stderr, "%s: command: DEMO %d\n", blurb(), hack_number + 1); - status = xscreensaver_command (GDK_DISPLAY(), XA_DEMO, hack_number + 1, - False, &err); + status = xscreensaver_command (s->dpy, XA_DEMO, hack_number + 1, + FALSE, &err); if (status < 0 && report_errors_p) { @@ -592,11 +690,8 @@ run_hack (state *s, int list_elt, Bool report_errors_p) if (status < 0) { char buf [255]; - if (err) - sprintf (buf, "Error:\n\n%s", err); - else - strcpy (buf, "Unknown error!"); - warning_dialog (s->toplevel_widget, buf, D_NONE, 100); + sprintf (buf, "%.100s", err ? err : _("Unknown error!")); + warning_dialog (s->window, _("Error"), buf); } } else @@ -604,44 +699,39 @@ run_hack (state *s, int list_elt, Bool report_errors_p) /* The error is that the daemon isn't running; offer to restart it. */ - const char *d = DisplayString (GDK_DISPLAY()); + const char *d = DisplayString (s->dpy); char msg [1024]; sprintf (msg, - _("Warning:\n\n" - "The XScreenSaver daemon doesn't seem to be running\n" + _("The XScreenSaver daemon doesn't seem to be running\n" "on display \"%.25s\". Launch it now?"), d); - warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1); + warning_dialog_1 (s->window, _("Warning"), msg, D_LAUNCH); } } if (err) free (err); - sensitize_menu_items (s, False); + sensitize_menu_items (s, FALSE); } -/* Button callbacks, referenced by xscreensaver.ui. - */ +/**************************************************************************** -/* File menu / Exit */ -G_MODULE_EXPORT void -exit_menu_cb (GtkAction *menu_action, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - flush_dialog_changes_and_save (s); - kill_preview_subproc (s, False); - gtk_main_quit (); -} + XScreenSaverWindow callbacks, referenced by demo.ui. -/* Close (X) button */ -static gboolean -wm_toplevel_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data) + ****************************************************************************/ + +/* File menu / Quit */ +G_MODULE_EXPORT void +quit_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = (state *) data; + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: quit menu\n", blurb()); flush_dialog_changes_and_save (s); - gtk_main_quit (); - return TRUE; + kill_preview_subproc (s, FALSE); + g_application_quit (G_APPLICATION ( + gtk_window_get_application (GTK_WINDOW (win)))); } @@ -649,7 +739,9 @@ wm_toplevel_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data) G_MODULE_EXPORT void about_menu_cb (GtkAction *menu_action, gpointer user_data) { - /* Let's just pop up the splash dialog. */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: about menu\n", blurb()); preview_theme_cb (NULL, user_data); } @@ -658,15 +750,17 @@ about_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void doc_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; char *help_command; + if (s->debug_p) fprintf (stderr, "%s: doc menu\n", blurb()); + if (!p->help_url || !*p->help_url) { - warning_dialog (s->toplevel_widget, - _("Error:\n\n" - "No Help URL has been specified.\n"), D_NONE, 100); + warning_dialog (GTK_WINDOW (win), _("Error"), + _("No Help URL has been specified.\n")); return; } @@ -687,8 +781,10 @@ doc_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void file_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ - sensitize_menu_items (s, False); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: file menu post\n", blurb()); + sensitize_menu_items (s, FALSE); } @@ -696,7 +792,9 @@ file_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void activate_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: activate menu\n", blurb()); run_cmd (s, XA_ACTIVATE, 0); } @@ -705,7 +803,9 @@ activate_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void lock_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: lock menu\n", blurb()); run_cmd (s, XA_LOCK, 0); } @@ -714,7 +814,9 @@ lock_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void kill_menu_cb (GtkAction *menu_action, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: kill menu\n", blurb()); run_cmd (s, XA_EXIT, 0); } @@ -723,11 +825,12 @@ kill_menu_cb (GtkAction *menu_action, gpointer user_data) G_MODULE_EXPORT void restart_menu_cb (GtkWidget *widget, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: restart menu\n", blurb()); + if (!s->dpy) return; flush_dialog_changes_and_save (s); - if (s->debug_p) - fprintf (stderr, "%s: command: EXIT\n", blurb()); - xscreensaver_command (GDK_DISPLAY(), XA_EXIT, 0, False, NULL); + xscreensaver_command (s->dpy, XA_EXIT, 0, FALSE, NULL); sleep (1); if (system ("xscreensaver --splash &") < 0) fprintf (stderr, "%s: fork error\n", blurb()); @@ -735,31 +838,33 @@ restart_menu_cb (GtkWidget *widget, gpointer user_data) await_xscreensaver (s); } + static Bool xscreensaver_running_p (state *s) { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; char *rversion = 0; + if (!dpy) return FALSE; server_xscreensaver_version (dpy, &rversion, 0, 0); if (!rversion) - return False; + return FALSE; free (rversion); - return True; + return TRUE; } static void await_xscreensaver (state *s) { int countdown = 5; - Bool ok = False; + Bool ok = FALSE; while (!ok && (--countdown > 0)) if (xscreensaver_running_p (s)) - ok = True; + ok = TRUE; else sleep (1); /* If it's not there yet, wait a second... */ - sensitize_menu_items (s, True); + sensitize_menu_items (s, TRUE); if (! ok) { @@ -769,41 +874,19 @@ await_xscreensaver (state *s) Bool root_p = (geteuid () == 0); strcpy (buf, - _("Error:\n\n" - "The xscreensaver daemon did not start up properly.\n" + _("The xscreensaver daemon did not start up properly.\n" "\n")); if (root_p) - strcat (buf, STFU -/* - _("You are running as root. This usually means that xscreensaver\n" - "was unable to contact your X server because access control is\n" - "turned on.\n" - "\n" - "Try running this command:\n" - "\n" - " xhost +localhost\n" - "\n" - "and then selecting `File / Restart Daemon'.\n" - "\n" - "Note that turning off access control will allow anyone logged\n" - "on to this machine to access your screen, which might be\n" - "considered a security problem. Please read the xscreensaver\n" - "manual and FAQ for more information.\n" - "\n" - "You shouldn't run X as root. Instead, you should log in as a\n" - "normal user, and `sudo' as necessary.") -*/ + strcat (buf, _("You are running as root. Don't do that. Instead, you should\n" "log in as a normal user and use `sudo' as necessary.") ); else strcat (buf, _("Please check your $PATH and permissions.")); - warning_dialog (s->toplevel_widget, buf, D_NONE, 1); + warning_dialog (s->window, _("Error"), buf); } - - force_dialog_repaint (s); } @@ -819,9 +902,10 @@ selected_list_element (state *s) static int demo_write_init_file (state *s, saver_preferences *p) { - Display *dpy = GDK_DISPLAY(); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + Display *dpy = s->dpy; - if (!write_init_file (dpy, p, s->short_version, False)) + if (!write_init_file (dpy, p, s->short_version, FALSE)) { if (s->debug_p) fprintf (stderr, "%s: wrote %s\n", blurb(), init_file_name()); @@ -831,14 +915,13 @@ demo_write_init_file (state *s, saver_preferences *p) { const char *f = init_file_name(); if (!f || !*f) - warning_dialog (s->toplevel_widget, - _("Error:\n\nCouldn't determine init file name!\n"), - D_NONE, 100); + warning_dialog (GTK_WINDOW (win), _("Error"), + _("Couldn't determine init file name!\n")); else { char *b = (char *) malloc (strlen(f) + 1024); - sprintf (b, _("Error:\n\nCouldn't write %s\n"), f); - warning_dialog (s->toplevel_widget, b, D_NONE, 100); + sprintf (b, _("Couldn't write %s\n"), f); + warning_dialog (GTK_WINDOW (win), _("Error"), b); free (b); } return -1; @@ -850,85 +933,38 @@ demo_write_init_file (state *s, saver_preferences *p) G_MODULE_EXPORT void run_this_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ - int list_elt = selected_list_element (s); - if (list_elt < 0) return; - flush_dialog_changes_and_save (s); - run_hack (s, list_elt, True); -} - - -/* The "Documentation" button on the Settings dialog */ -G_MODULE_EXPORT void -manual_cb (GtkButton *button, gpointer user_data) -{ - Display *dpy = GDK_DISPLAY(); - state *s = global_state_kludge; /* I hate C so much... */ - saver_preferences *p = &s->prefs; - GtkWidget *list_widget = name_to_widget (s, "list"); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; int list_elt = selected_list_element (s); - int hack_number; - char *name, *name2, *cmd, *str; - char *oname = 0; if (list_elt < 0) return; - hack_number = s->list_elt_to_hack_number[list_elt]; - + if (s->debug_p) fprintf (stderr, "%s: preview button\n", blurb()); flush_dialog_changes_and_save (s); - ensure_selected_item_visible (list_widget); - - name = strdup (p->screenhacks[hack_number]->command); - name2 = name; - oname = name; - while (isspace (*name2)) name2++; - str = name2; - while (*str && !isspace (*str)) str++; - *str = 0; - str = strrchr (name2, '/'); - if (str) name2 = str+1; - - cmd = get_string_resource (dpy, "manualCommand", "ManualCommand"); - if (cmd) - { - char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100); - strcpy (cmd2, "( "); - sprintf (cmd2 + strlen (cmd2), - cmd, - name2, name2, name2, name2); - strcat (cmd2, " ) &"); - if (system (cmd2) < 0) - fprintf (stderr, "%s: fork error\n", blurb()); - free (cmd2); - } - else - { - warning_dialog (GTK_WIDGET (button), - _("Error:\n\nno `manualCommand' resource set."), - D_NONE, 100); - } - - free (oname); + run_hack (s, list_elt, TRUE); } static void force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p) { - GtkWidget *parent = name_to_widget (s, "scroller"); - gboolean was = GET_SENSITIVE (parent); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkWidget *parent = win->scroller; + gboolean was = gtk_widget_get_sensitive (parent); GtkTreeIter iter; GtkTreeModel *model; GtkTreeSelection *selection; - if (!was) gtk_widget_set_sensitive (parent, True); + if (!was) gtk_widget_set_sensitive (parent, TRUE); model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); if (!model) abort(); if (gtk_tree_model_iter_nth_child (model, &iter, NULL, list_elt)) { selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); gtk_tree_selection_select_iter (selection, &iter); + if (s->debug_p) + fprintf (stderr, "%s: select list elt %d\n", blurb(), list_elt); } if (scroll_p) ensure_selected_item_visible (GTK_WIDGET (list)); - if (!was) gtk_widget_set_sensitive (parent, False); + if (!was) gtk_widget_set_sensitive (parent, FALSE); } @@ -936,13 +972,14 @@ force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p) G_MODULE_EXPORT void run_next_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ - /* saver_preferences *p = &s->prefs; */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; Bool ops = s->preview_suppressed_p; - - GtkWidget *list_widget = name_to_widget (s, "list"); + GtkWidget *list_widget = win->list; int list_elt = selected_list_element (s); + if (s->debug_p) fprintf (stderr, "%s: down arrow\n", blurb()); + if (list_elt < 0) list_elt = 0; else @@ -951,13 +988,13 @@ run_next_cb (GtkButton *button, gpointer user_data) if (list_elt >= s->list_count) list_elt = 0; - s->preview_suppressed_p = True; + s->preview_suppressed_p = TRUE; flush_dialog_changes_and_save (s); - force_list_select_item (s, list_widget, list_elt, True); + force_list_select_item (s, list_widget, list_elt, TRUE); populate_demo_window (s, list_elt); populate_popup_window (s); - run_hack (s, list_elt, False); + run_hack (s, list_elt, FALSE); s->preview_suppressed_p = ops; } @@ -967,13 +1004,14 @@ run_next_cb (GtkButton *button, gpointer user_data) G_MODULE_EXPORT void run_prev_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ - /* saver_preferences *p = &s->prefs; */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; Bool ops = s->preview_suppressed_p; - - GtkWidget *list_widget = name_to_widget (s, "list"); + GtkWidget *list_widget = win->list; int list_elt = selected_list_element (s); + if (s->debug_p) fprintf (stderr, "%s: up arrow\n", blurb()); + if (list_elt < 0) list_elt = s->list_count - 1; else @@ -982,20 +1020,20 @@ run_prev_cb (GtkButton *button, gpointer user_data) if (list_elt < 0) list_elt = s->list_count - 1; - s->preview_suppressed_p = True; + s->preview_suppressed_p = TRUE; flush_dialog_changes_and_save (s); - force_list_select_item (s, list_widget, list_elt, True); + force_list_select_item (s, list_widget, list_elt, TRUE); populate_demo_window (s, list_elt); populate_popup_window (s); - run_hack (s, list_elt, False); + run_hack (s, list_elt, FALSE); s->preview_suppressed_p = ops; } -/* Writes the given settings into prefs. - Returns true if there was a change, False otherwise. +/* Writes the settings of the given hack into prefs. + Returns true if there was a change, FALSE otherwise. command and/or visual may be 0, or enabled_p may be -1, meaning "no change". */ static Bool @@ -1006,7 +1044,7 @@ flush_changes (state *s, const char *visual) { saver_preferences *p = &s->prefs; - Bool changed = False; + Bool changed = FALSE; screenhack *hack; int hack_number; if (list_elt < 0 || list_elt >= s->list_count) @@ -1019,7 +1057,7 @@ flush_changes (state *s, enabled_p != hack->enabled_p) { hack->enabled_p = enabled_p; - changed = True; + changed = TRUE; if (s->debug_p) fprintf (stderr, "%s: \"%s\": enabled => %d\n", blurb(), hack->name, enabled_p); @@ -1031,7 +1069,7 @@ flush_changes (state *s, { if (hack->command) free (hack->command); hack->command = strdup (command); - changed = True; + changed = TRUE; if (s->debug_p) fprintf (stderr, "%s: \"%s\": command => \"%s\"\n", blurb(), hack->name, command); @@ -1047,7 +1085,7 @@ flush_changes (state *s, { if (hack->visual) free (hack->visual); hack->visual = strdup (visual); - changed = True; + changed = TRUE; if (s->debug_p) fprintf (stderr, "%s: \"%s\": visual => \"%s\"\n", blurb(), hack->name, visual); @@ -1068,7 +1106,7 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) { int value; if (!sec_p || strchr (line, ':')) - value = parse_time ((char *) line, sec_p, True); + value = parse_time ((char *) line, sec_p, TRUE); else { char c; @@ -1082,11 +1120,9 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) if (value < 0) { char b[255]; - sprintf (b, - _("Error:\n\n" - "Unparsable time format: \"%s\"\n"), + sprintf (b, _("Unparsable time format: \"%.100s\"\n"), line); - warning_dialog (s->toplevel_widget, b, D_NONE, 100); + warning_dialog (s->window, _("Error"), b); } else *store = value; @@ -1094,155 +1130,6 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p) } -static Bool -directory_p (const char *path) -{ - struct stat st; - if (!path || !*path) - return False; - else if (stat (path, &st)) - return False; - else if (!S_ISDIR (st.st_mode)) - return False; - else - return True; -} - -static Bool -file_p (const char *path) -{ - struct stat st; - if (!path || !*path) - return False; - else if (stat (path, &st)) - return False; - else if (S_ISDIR (st.st_mode)) - return False; - else - return True; -} - -/* See if the directory has at least one image file under it. - Recurses to at most the given depth, chasing symlinks. - To do this properly would mean running "xscreensaver-getimage-file" - and seeing if it found anything, but that might take a long time to - build the cache the first time, so this is close enough. - */ -static Bool -image_files_p (const char *path, int max_depth) -{ - const char * const exts[] = { - "jpg", "jpeg", "pjpeg", "pjpg", "png", "gif", - "tif", "tiff", "xbm", "xpm", "svg", - }; - struct dirent *de; - Bool ok = False; - DIR *dir = opendir (path); - if (!dir) return False; - - while (!ok && (de = readdir (dir))) - { - struct stat st; - const char *f = de->d_name; - char *f2; - if (*f == '.') continue; - - f2 = (char *) malloc (strlen(path) + strlen(f) + 10); - strcpy (f2, path); - strcat (f2, "/"); - strcat (f2, f); - - if (!stat (f2, &st)) - { - if (S_ISDIR (st.st_mode)) - { - if (max_depth > 0 && image_files_p (f2, max_depth - 1)) - ok = True; - } - else - { - int i; - const char *ext = strrchr (f, '.'); - if (ext) - for (i = 0; i < countof(exts); i++) - if (!strcasecmp (ext+1, exts[i])) - { - /* fprintf (stderr, "%s: found %s\n", blurb(), f2); */ - ok = True; - break; - } - } - } - - free (f2); - } - - closedir (dir); - return ok; -} - - -static char * -normalize_directory (const char *path) -{ - int L; - char *p2, *s; - if (!path || !*path) return 0; - L = strlen (path); - p2 = (char *) malloc (L + 2); - strcpy (p2, path); - if (p2[L-1] == '/') /* remove trailing slash */ - p2[--L] = 0; - - for (s = p2; s && *s; s++) - { - if (*s == '/' && - (!strncmp (s, "/../", 4) || /* delete "XYZ/../" */ - !strncmp (s, "/..\000", 4))) /* delete "XYZ/..$" */ - { - char *s0 = s; - while (s0 > p2 && s0[-1] != '/') - s0--; - if (s0 > p2) - { - s0--; - s += 3; - /* strcpy (s0, s); */ - memmove(s0, s, strlen(s) + 1); - s = s0-1; - } - } - else if (*s == '/' && !strncmp (s, "/./", 3)) { /* delete "/./" */ - /* strcpy (s, s+2), s--; */ - memmove(s, s+2, strlen(s+2) + 1); - s--; - } - else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */ - *s = 0, s--; - } - - /* - Normalize consecutive slashes. - Ignore doubled slashes after ":" to avoid mangling URLs. - */ - - for (s = p2; s && *s; s++){ - if (*s == ':') continue; - if (!s[1] || !s[2]) continue; - while (s[1] == '/' && s[2] == '/') - /* strcpy (s+1, s+2); */ - memmove (s+1, s+2, strlen(s+2) + 1); - } - - /* and strip trailing whitespace for good measure. */ - L = strlen(p2); - while (isspace(p2[L-1])) - p2[--L] = 0; - - return p2; -} - - typedef struct { state *s; int i; @@ -1264,7 +1151,7 @@ flush_checkbox (GtkTreeModel *model, if (flush_changes (closure->s, closure->i, checked, 0, 0)) - *closure->changed = True; + *closure->changed = TRUE; closure->i++; @@ -1298,21 +1185,20 @@ theme_name_strip (const char *s) static Bool flush_dialog_changes_and_save (state *s) { - Display *dpy = GDK_DISPLAY(); saver_preferences *p = &s->prefs; saver_preferences P2, *p2 = &P2; - GtkTreeView *list_widget = GTK_TREE_VIEW (name_to_widget (s, "list")); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkTreeView *list_widget = GTK_TREE_VIEW (win->list); GtkTreeModel *model = gtk_tree_view_get_model (list_widget); FlushForeachClosure closure; - Bool changed = False; - GtkWidget *w; + Bool changed = FALSE; - if (s->saving_p) return False; - s->saving_p = True; + if (s->saving_p) return FALSE; + s->saving_p = TRUE; *p2 = *p; - /* Flush any checkbox changes in the list down into the prefs struct. + /* Flush any checkbox changes in the list down into the s2 prefs struct. */ closure.s = s; closure.changed = &changed; @@ -1322,64 +1208,56 @@ flush_dialog_changes_and_save (state *s) /* Flush the non-hack-specific settings down into the prefs struct. */ -# define SECONDS(FIELD,NAME) \ - w = name_to_widget (s, (NAME)); \ - hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (w)), (FIELD), True) - -# define MINUTES(FIELD,NAME) \ - w = name_to_widget (s, (NAME)); \ - hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (w)), (FIELD), False) - -# define CHECKBOX(FIELD,NAME) \ - w = name_to_widget (s, (NAME)); \ - (FIELD) = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)) - -# define PATHNAME(FIELD,NAME) \ - w = name_to_widget (s, (NAME)); \ - (FIELD) = normalize_directory (gtk_entry_get_text (GTK_ENTRY (w))) - -# define TEXT(FIELD,NAME) \ - w = name_to_widget (s, (NAME)); \ - (FIELD) = (char *) g_strdup(gtk_entry_get_text (GTK_ENTRY (w))) - - MINUTES (&p2->timeout, "timeout_spinbutton"); - MINUTES (&p2->cycle, "cycle_spinbutton"); - CHECKBOX (p2->lock_p, "lock_button"); - MINUTES (&p2->lock_timeout, "lock_spinbutton"); - - CHECKBOX (p2->dpms_enabled_p, "dpms_button"); - CHECKBOX (p2->dpms_quickoff_p, "dpms_quickoff_button"); - MINUTES (&p2->dpms_standby, "dpms_standby_spinbutton"); - MINUTES (&p2->dpms_suspend, "dpms_suspend_spinbutton"); - MINUTES (&p2->dpms_off, "dpms_off_spinbutton"); - - CHECKBOX (p2->grab_desktop_p, "grab_desk_button"); - CHECKBOX (p2->grab_video_p, "grab_video_button"); - CHECKBOX (p2->random_image_p, "grab_image_button"); - PATHNAME (p2->image_directory, "image_text"); - -#if 0 - CHECKBOX (p2->verbose_p, "verbose_button"); - CHECKBOX (p2->splash_p, "splash_button"); -#endif +# define SECONDS(PREF,WIDGET) \ + hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (win->WIDGET)), \ + &(PREF), TRUE) +# define MINUTES(PREF,WIDGET) \ + hack_time_text (s, gtk_entry_get_text (GTK_ENTRY (win->WIDGET)), \ + &(PREF), FALSE) +# define CHECKBOX(PREF,WIDGET) \ + (PREF) = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (win->WIDGET)) +# define PATHNAME(PREF,WIDGET,DIRP) \ + (PREF) = pathname_tilde ( \ + gtk_entry_get_text (GTK_ENTRY (win->WIDGET)), TRUE, (DIRP)) +# define TEXT(PREF,WIDGET) \ + (PREF) = (char *) g_strdup (gtk_entry_get_text (GTK_ENTRY (win->WIDGET))) + + MINUTES (p2->timeout, timeout_spinbutton); + MINUTES (p2->cycle, cycle_spinbutton); + CHECKBOX (p2->lock_p, lock_button); + MINUTES (p2->lock_timeout, lock_spinbutton); + + CHECKBOX (p2->dpms_enabled_p, dpms_button); + CHECKBOX (p2->dpms_quickoff_p, dpms_quickoff_button); + MINUTES (p2->dpms_standby, dpms_standby_spinbutton); + MINUTES (p2->dpms_suspend, dpms_suspend_spinbutton); + MINUTES (p2->dpms_off, dpms_off_spinbutton); + + CHECKBOX (p2->grab_desktop_p, grab_desk_button); + CHECKBOX (p2->grab_video_p, grab_video_button); + CHECKBOX (p2->random_image_p, grab_image_button); + PATHNAME (p2->image_directory, image_text, TRUE); { - Bool v = False; - CHECKBOX (v, "text_host_radio"); if (v) p2->tmode = TEXT_DATE; - CHECKBOX (v, "text_radio"); if (v) p2->tmode = TEXT_LITERAL; - CHECKBOX (v, "text_file_radio"); if (v) p2->tmode = TEXT_FILE; - CHECKBOX (v, "text_program_radio"); if (v) p2->tmode = TEXT_PROGRAM; - CHECKBOX (v, "text_url_radio"); if (v) p2->tmode = TEXT_URL; - TEXT (p2->text_literal, "text_entry"); - PATHNAME (p2->text_file, "text_file_entry"); - PATHNAME (p2->text_program, "text_program_entry"); - PATHNAME (p2->text_program, "text_program_entry"); - TEXT (p2->text_url, "text_url_entry"); + Bool v = FALSE; + Bool od = s->debug_p; + s->debug_p = FALSE; + CHECKBOX (v, text_host_radio); if (v) p2->tmode = TEXT_DATE; + CHECKBOX (v, text_radio); if (v) p2->tmode = TEXT_LITERAL; + CHECKBOX (v, text_file_radio); if (v) p2->tmode = TEXT_FILE; + CHECKBOX (v, text_program_radio); if (v) p2->tmode = TEXT_PROGRAM; + CHECKBOX (v, text_url_radio); if (v) p2->tmode = TEXT_URL; + s->debug_p = od; } - CHECKBOX (p2->fade_p, "fade_button"); - CHECKBOX (p2->unfade_p, "unfade_button"); - SECONDS (&p2->fade_seconds, "fade_spinbutton"); + TEXT (p2->text_literal, text_entry); + PATHNAME (p2->text_file, text_file_entry, FALSE); + PATHNAME (p2->text_program, text_program_entry, FALSE); + TEXT (p2->text_url, text_url_entry); + + CHECKBOX (p2->fade_p, fade_button); + CHECKBOX (p2->unfade_p, unfade_button); + SECONDS (p2->fade_seconds, fade_spinbutton); # undef SECONDS # undef MINUTES @@ -1389,7 +1267,7 @@ flush_dialog_changes_and_save (state *s) /* Map the mode menu to `saver_mode' enum values. */ { - GtkComboBox *opt = GTK_COMBO_BOX (name_to_widget (s, "mode_menu")); + GtkComboBox *opt = GTK_COMBO_BOX (win->mode_menu); int menu_elt = gtk_combo_box_get_active (opt); if (menu_elt < 0 || menu_elt >= countof(mode_menu_order)) abort(); p2->mode = mode_menu_order[menu_elt]; @@ -1405,10 +1283,11 @@ flush_dialog_changes_and_save (state *s) /* Theme menu. */ { - GtkComboBox *cbox = GTK_COMBO_BOX (name_to_widget (s, "theme_menu")); + Display *dpy = s->dpy; + GtkComboBox *cbox = GTK_COMBO_BOX (win->theme_menu); char *themes = get_string_resource (dpy, "themeNames", "ThemeNames"); int menu_index = gtk_combo_box_get_active (cbox); - char *token = themes; + char *token = themes ? themes : "default"; char *name, *last; int i = 0; while ((name = strtok_r (token, ",", &last))) @@ -1422,7 +1301,7 @@ flush_dialog_changes_and_save (state *s) free (p->dialog_theme); p2->dialog_theme = name2; if (s->debug_p) - fprintf (stderr, "%s: theme => \"%s\"\n", blurb(), + fprintf (stderr, "%s: theme => \"%s\"\n", blurb(), p2->dialog_theme); } else @@ -1434,74 +1313,76 @@ flush_dialog_changes_and_save (state *s) } } -# define COPY(field, name) \ - if (p->field != p2->field) { \ - changed = True; \ - if (s->debug_p) \ - fprintf (stderr, "%s: %s => %ld\n", blurb(), \ - name, (unsigned long) p2->field); \ - } \ - p->field = p2->field - - COPY(mode, "mode"); - COPY(selected_hack, "selected_hack"); - - COPY(timeout, "timeout"); - COPY(cycle, "cycle"); - COPY(lock_p, "lock_p"); - COPY(lock_timeout, "lock_timeout"); - - COPY(dpms_enabled_p, "dpms_enabled_p"); - COPY(dpms_quickoff_p, "dpms_quickoff_enabled_p"); - COPY(dpms_standby, "dpms_standby"); - COPY(dpms_suspend, "dpms_suspend"); - COPY(dpms_off, "dpms_off"); - -#if 0 - COPY(verbose_p, "verbose_p"); - COPY(splash_p, "splash_p"); -#endif - - COPY(tmode, "tmode"); - - COPY(install_cmap_p, "install_cmap_p"); - COPY(fade_p, "fade_p"); - COPY(unfade_p, "unfade_p"); - COPY(fade_seconds, "fade_seconds"); - - COPY(grab_desktop_p, "grab_desktop_p"); - COPY(grab_video_p, "grab_video_p"); - COPY(random_image_p, "random_image_p"); - - COPY(dialog_theme, "dialog_theme"); + /* Copy any changes from s2 into s, and log them. + */ +# undef STR +# define STR(S) #S +# define COPY(FIELD) \ + if (p->FIELD != p2->FIELD) { \ + changed = TRUE; \ + if (s->debug_p) \ + fprintf (stderr, "%s: %s: %ld => %ld\n", blurb(),\ + STR(FIELD), (unsigned long) p->FIELD, \ + (unsigned long) p2->FIELD); \ + } \ + p->FIELD = p2->FIELD + + COPY(mode); + COPY(selected_hack); + + COPY(timeout); + COPY(cycle); + COPY(lock_p); + COPY(lock_timeout); + + COPY(dpms_enabled_p); + COPY(dpms_quickoff_p); + COPY(dpms_standby); + COPY(dpms_suspend); + COPY(dpms_off); + + COPY(tmode); + + COPY(install_cmap_p); + COPY(fade_p); + COPY(unfade_p); + COPY(fade_seconds); + + COPY(grab_desktop_p); + COPY(grab_video_p); + COPY(random_image_p); + + COPY(dialog_theme); # undef COPY -# define COPYSTR(FIELD,NAME) \ - if (!p->FIELD || \ - !p2->FIELD || \ - strcmp(p->FIELD, p2->FIELD)) \ - { \ - changed = True; \ - if (s->debug_p) \ - fprintf (stderr, "%s: %s => \"%s\"\n", blurb(), NAME, p2->FIELD); \ - } \ - if (p->FIELD && p->FIELD != p2->FIELD) \ - free (p->FIELD); \ - p->FIELD = p2->FIELD; \ +# define COPYSTR(FIELD) \ + if (!p->FIELD || \ + !p2->FIELD || \ + strcmp(p->FIELD, p2->FIELD)) \ + { \ + changed = TRUE; \ + if (s->debug_p) \ + fprintf (stderr, "%s: %s => \"%s\"\n", blurb(), \ + STR(FIELD), p2->FIELD); \ + } \ + if (p->FIELD && p->FIELD != p2->FIELD) \ + free (p->FIELD); \ + p->FIELD = p2->FIELD; \ p2->FIELD = 0 - COPYSTR(image_directory, "image_directory"); - COPYSTR(text_literal, "text_literal"); - COPYSTR(text_file, "text_file"); - COPYSTR(text_program, "text_program"); - COPYSTR(text_url, "text_url"); + COPYSTR(image_directory); + COPYSTR(text_literal); + COPYSTR(text_file); + COPYSTR(text_program); + COPYSTR(text_url); # undef COPYSTR populate_prefs_page (s); if (changed) { - sync_server_dpms_settings (GDK_DISPLAY(), p); + if (s->dpy) + sync_server_dpms_settings (s->dpy, p); demo_write_init_file (s, p); /* Tell the xscreensaver daemon to wake up and reload the init file, @@ -1509,129 +1390,69 @@ flush_dialog_changes_and_save (state *s) until the *old* timeout had expired before reloading. */ if (s->debug_p) fprintf (stderr, "%s: command: DEACTIVATE\n", blurb()); - xscreensaver_command (GDK_DISPLAY(), XA_DEACTIVATE, 0, 0, 0); + if (s->dpy) + xscreensaver_command (s->dpy, XA_DEACTIVATE, 0, 0, 0); } - s->saving_p = False; + s->saving_p = FALSE; return changed; } -/* Flush out any changes made in the popup dialog box (where changes - take place only when the OK button is clicked.) - */ -static Bool -flush_popup_changes_and_save (state *s) +/* Called when any field in the prefs dialog may have been changed. + Referenced by many items in demo.ui. */ +G_MODULE_EXPORT gboolean +pref_changed_cb (GtkWidget *widget, gpointer user_data) { - Bool changed = False; - saver_preferences *p = &s->prefs; - int list_elt = selected_list_element (s); - - GtkEntry *cmd = GTK_ENTRY (name_to_widget (s, "cmd_text")); - GtkComboBoxEntry *vis = - GTK_COMBO_BOX_ENTRY (name_to_widget (s, "visual_combo")); - GtkEntry *visent = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (vis))); - - const char *visual = gtk_entry_get_text (visent); - const char *command = gtk_entry_get_text (cmd); - - char c; - unsigned long id; - - if (s->saving_p) return False; - s->saving_p = True; - - if (list_elt < 0) - goto DONE; - - if (maybe_reload_init_file (s) != 0) - { - changed = True; - goto DONE; - } - - /* Sanity-check and canonicalize whatever the user typed into the combo box. - */ - if (!strcasecmp (visual, "")) visual = ""; - else if (!strcasecmp (visual, "any")) visual = ""; - else if (!strcasecmp (visual, "default")) visual = "Default"; - else if (!strcasecmp (visual, "default-n")) visual = "Default-N"; - else if (!strcasecmp (visual, "default-i")) visual = "Default-I"; - else if (!strcasecmp (visual, "best")) visual = "Best"; - else if (!strcasecmp (visual, "mono")) visual = "Mono"; - else if (!strcasecmp (visual, "monochrome")) visual = "Mono"; - else if (!strcasecmp (visual, "gray")) visual = "Gray"; - else if (!strcasecmp (visual, "grey")) visual = "Gray"; - else if (!strcasecmp (visual, "color")) visual = "Color"; - else if (!strcasecmp (visual, "gl")) visual = "GL"; - else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray"; - else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor"; - else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor"; - else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale"; - else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale"; - else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor"; - else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor"; - else if (1 == sscanf (visual, " %lu %c", &id, &c)) ; - else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ; - else - { - gdk_beep (); /* unparsable */ - visual = ""; - gtk_entry_set_text (visent, _("Any")); - } + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; - changed = flush_changes (s, list_elt, -1, command, visual); - if (changed) + if (s->debug_p) { - changed = demo_write_init_file (s, p); - - /* Do this to re-launch the hack if (and only if) the command line - has changed. */ - populate_demo_window (s, selected_list_element (s)); + if (s->initializing_p) + fprintf (stderr, "%s: (pref changed)\n", blurb()); + else + fprintf (stderr, "%s: pref changed\n", blurb()); } - DONE: - s->saving_p = False; - return changed; -} - - -/* Called when any field in the prefs dialog may have been changed. - Referenced by many items in xscreensaver.ui. */ -G_MODULE_EXPORT void -pref_changed_cb (GtkWidget *widget, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ if (! s->initializing_p) { - s->initializing_p = True; + s->initializing_p = TRUE; flush_dialog_changes_and_save (s); - s->initializing_p = False; + s->initializing_p = FALSE; } + return GDK_EVENT_PROPAGATE; } + /* Same as pref_changed_cb but different. */ G_MODULE_EXPORT gboolean pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { pref_changed_cb (widget, user_data); - return FALSE; + return GDK_EVENT_PROPAGATE; } + /* Callback on menu items in the "mode" options menu. */ G_MODULE_EXPORT void mode_menu_item_cb (GtkWidget *widget, gpointer user_data) { - state *s = (state *) user_data; + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; - GtkWidget *list = name_to_widget (s, "list"); + GtkWidget *list = win->list; int list_elt; int menu_index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); saver_mode new_mode = mode_menu_order[menu_index]; + if (s->initializing_p) return; /* Called as a spurious side-effect */ + + if (s->debug_p) fprintf (stderr, "%s: mode menu\n", blurb()); + /* Keep the same list element displayed as before; except if we're switching *to* "one screensaver" mode from any other mode, set "the one" to be that which is currently selected. @@ -1645,7 +1466,7 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) p->mode = new_mode; populate_demo_window (s, list_elt); populate_popup_window (s); - force_list_select_item (s, list, list_elt, True); + force_list_select_item (s, list, list_elt, TRUE); p->mode = old_mode; /* put it back, so the init file gets written */ } @@ -1653,12 +1474,42 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data) } +/* Remove the "random-same" item from the screen saver mode menu + (we don't display that unless there are multiple screens.) + */ +static void +hide_mode_menu_random_same (state *s) +{ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkComboBox *opt = GTK_COMBO_BOX (win->mode_menu); + GtkTreeModel *list = gtk_combo_box_get_model (opt); + unsigned int i; + for (i = 0; i < countof(mode_menu_order); i++) + { + if (mode_menu_order[i] == RANDOM_HACKS_SAME) + { + GtkTreeIter iter; + gtk_tree_model_iter_nth_child (list, &iter, NULL, i); + gtk_list_store_remove (GTK_LIST_STORE (list), &iter); + break; + } + } + + /* recompute option-menu size */ + gtk_widget_unrealize (GTK_WIDGET (opt)); + gtk_widget_realize (GTK_WIDGET (opt)); +} + + /* Called when a new tab is selected. */ G_MODULE_EXPORT void -switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, +switch_page_cb (GtkNotebook *notebook, GtkWidget *page, gint page_num, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + + if (s->debug_p) fprintf (stderr, "%s: tab changed\n", blurb()); pref_changed_cb (GTK_WIDGET (notebook), user_data); /* If we're switching to page 0, schedule the current hack to be run. @@ -1672,38 +1523,44 @@ switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, schedule_preview (s, 0); } + /* Called when a line is double-clicked in the saver list. */ static void -list_activated_cb (GtkTreeView *list, - GtkTreePath *path, - GtkTreeViewColumn *column, - gpointer data) +list_activated_cb (GtkTreeView *list, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer data) { state *s = data; char *str; int list_elt; - if (gdk_pointer_is_grabbed()) return; + if (s->debug_p) fprintf (stderr, "%s: list activated\n", blurb()); + + /* I did this in Gtk 2 and I don't remember why: + if (gdk_pointer_is_grabbed()) return; + I don't understand how to use gdk_display_device_is_grabbed(). + */ str = gtk_tree_path_to_string (path); list_elt = strtol (str, NULL, 10); g_free (str); if (list_elt >= 0) - run_hack (s, list_elt, True); + run_hack (s, list_elt, TRUE); } /* Called when a line is selected/highlighted in the saver list. */ static void list_select_changed_cb (GtkTreeSelection *selection, gpointer data) { - state *s = (state *)data; + state *s = (state *) data; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; char *str; int list_elt; + if (s->debug_p) fprintf (stderr, "%s: list selection changed\n", blurb()); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; @@ -1732,14 +1589,13 @@ list_select_changed_cb (GtkTreeSelection *selection, gpointer data) */ static void list_checkbox_cb (GtkCellRendererToggle *toggle, - gchar *path_string, - gpointer data) + gchar *path_string, gpointer data) { state *s = (state *) data; - GtkScrolledWindow *scroller = - GTK_SCROLLED_WINDOW (name_to_widget (s, "scroller")); - GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (win->scroller); + GtkTreeView *list = GTK_TREE_VIEW (win->list); GtkTreeModel *model = gtk_tree_view_get_model (list); GtkTreePath *path = gtk_tree_path_new_from_string (path_string); GtkTreeIter iter; @@ -1749,6 +1605,8 @@ list_checkbox_cb (GtkCellRendererToggle *toggle, int list_elt; + if (s->debug_p) fprintf (stderr, "%s: list checkbox\n", blurb()); + if (!gtk_tree_model_get_iter (model, &iter, path)) { g_warning ("bad path: %s", path_string); @@ -1768,10 +1626,10 @@ list_checkbox_cb (GtkCellRendererToggle *toggle, /* remember previous scroll position of the top of the list */ adj = gtk_scrolled_window_get_vadjustment (scroller); - scroll_top = GET_ADJ_VALUE (adj); + scroll_top = gtk_adjustment_get_value (adj); flush_dialog_changes_and_save (s); - force_list_select_item (s, GTK_WIDGET (list), list_elt, False); + force_list_select_item (s, GTK_WIDGET (list), list_elt, FALSE); populate_demo_window (s, list_elt); populate_popup_window (s); @@ -1806,99 +1664,102 @@ validate_image_directory_quick (state *s) if (!warn) return; sprintf (buf, - _("Warning: %s:\n\n" - "\"%.100s\"\n\n" + _("%.100s:\n\n" + " %.100s\n\n" "Select the 'Advanced' tab and choose a directory with some\n" "pictures in it, or you're going to see a lot of boring colorbars!"), warn, - p->image_directory); - warning_dialog (s->toplevel_widget, buf, D_NONE, 3); + (p->image_directory ? p->image_directory : "")); + warning_dialog (s->window, _("Warning"), buf); } -static Bool validate_image_directory_cancelled_p; - /* "Cancel" button on the validate image directory progress dialog. */ static void -validate_image_directory_cancel_cb (GtkWidget *widget, gpointer user_data) +validate_image_directory_cancel_cb (GtkDialog *dialog, gint response_id, + gpointer user_data) { - validate_image_directory_cancelled_p = True; - warning_dialog_dismiss_cb (widget, user_data); + Bool *closed = (Bool *) user_data; + *closed = TRUE; + gtk_widget_destroy (GTK_WIDGET (dialog)); } -/* Close (X) button on the validate image directory progress dialog. */ -static gboolean -validate_image_directory_close_cb (GtkWidget *widget, GdkEvent *event, - gpointer data) + +typedef struct { + GtkWidget *dialog; + int timer_id; +} validate_timer_closure; + +static int +validate_timer_show (gpointer data) { - validate_image_directory_cancel_cb (widget, data); - return TRUE; + validate_timer_closure *vtc = (validate_timer_closure *) data; + gtk_widget_show_all (vtc->dialog); + vtc->timer_id = 0; + return FALSE; } - /* If the directory or URL does not have images in it, pop up a warning dialog and return false. This happens when the imageDirectory preference is edited, and might be slow. + + It does this by running "xscreensaver-getimage-file", which has the side + effect of populating the image cache for that directory. Since that will + take a while if there are a lot of files, this also pops up a progress + dialog with a spinner in it, and a cancel button. That progress dialog + only pops up if the validation has already been running for a little + while, so that it doesn't flicker for small or pre-cached directories. */ static Bool validate_image_directory (state *s, const char *path) { - GtkWidget *parent = s->toplevel_widget; - GtkWidget *dialog = gtk_dialog_new (); - GtkWidget *label = 0; - GtkWidget *cancel = 0; + validate_timer_closure vtc; char buf[1024]; char err[1024]; + GtkWidget *dialog, *content_area, *label, *spinner; + int margin = 32; + Bool closed_p = FALSE; - sprintf (buf, _("Populating image cache for \"%.100s\"..."), path); + dialog = gtk_dialog_new_with_buttons (_("XScreenSaver Image Cache"), + s->window, + GTK_DIALOG_DESTROY_WITH_PARENT, + _("_Cancel"), GTK_RESPONSE_CLOSE, + NULL); + sprintf (buf, _("Populating image cache for \"%.100s\"..."), path); + content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); label = gtk_label_new (buf); - gtk_label_set_selectable (GTK_LABEL (label), TRUE); - gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - gtk_widget_show (label); - - label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - gtk_widget_show (label); - - label = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))), - label, TRUE, TRUE, 0); - - cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - gtk_container_add (GTK_CONTAINER (label), cancel); - - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 10); - gtk_window_set_title (GTK_WINDOW (dialog), progclass); - SET_CAN_DEFAULT (cancel); - gtk_widget_show (cancel); - gtk_widget_grab_focus (cancel); - gtk_widget_show (label); - gtk_widget_show (dialog); - - validate_image_directory_cancelled_p = False; - - gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked", - GTK_SIGNAL_FUNC (validate_image_directory_cancel_cb), - (gpointer) dialog); - gtk_signal_connect (GTK_OBJECT (dialog), "delete_event", - GTK_SIGNAL_FUNC (validate_image_directory_close_cb), - (gpointer *) dialog); - - gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)), - GET_WINDOW (GTK_WIDGET (parent))); - - gtk_window_present (GTK_WINDOW (dialog)); + + gtk_widget_set_margin_start (label, margin); + gtk_widget_set_margin_end (label, margin); + gtk_widget_set_margin_top (label, margin); + gtk_widget_set_margin_bottom (label, margin / 2); + gtk_container_add (GTK_CONTAINER (content_area), label); + + spinner = gtk_spinner_new(); + gtk_spinner_start (GTK_SPINNER (spinner)); + gtk_container_add (GTK_CONTAINER (content_area), spinner); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + g_signal_connect (dialog, "response", + G_CALLBACK (validate_image_directory_cancel_cb), + &closed_p); + g_signal_connect (dialog, "close", + G_CALLBACK (validate_image_directory_cancel_cb), + &closed_p); + + /* Only pop up the dialog box with the spinner if this has already taken + a little while, so that if it completes immediately, we don't flicker. + */ + vtc.dialog = dialog; + vtc.timer_id = g_timeout_add (1000, validate_timer_show, &vtc); while (gtk_events_pending ()) /* Paint the window now. */ gtk_main_iteration (); { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; pid_t forked; int fds [2]; int in, out; @@ -1971,7 +1832,7 @@ validate_image_directory (state *s, const char *path) fd_set rset; struct timeval tv; tv.tv_sec = 0; - tv.tv_usec = 1000000 / 10; + tv.tv_usec = 1000000 / 10; /* Repaint widgets at 10 fps */ FD_ZERO (&rset); FD_SET (in, &rset); if (0 < select (in+1, &rset, 0, 0, &tv)) @@ -1980,7 +1841,7 @@ validate_image_directory (state *s, const char *path) if (n <= 0) { if (s->debug_p) - fprintf (stderr, "%s: read EOF\n", blurb()); + fprintf (stderr, "%s: %s: read EOF\n", blurb(), av[0]); break; } else @@ -1990,15 +1851,16 @@ validate_image_directory (state *s, const char *path) *ss = 0; if (s->debug_p) - fprintf (stderr, "%s: read: \"%s\"\n", blurb(), - ss - n); + fprintf (stderr, "%s: %s: read: \"%s\"\n", blurb(), + av[0], ss - n); } } + /* Service Gtk events and timers */ while (gtk_events_pending ()) gtk_main_iteration (); - if (validate_image_directory_cancelled_p) + if (closed_p) { kill (forked, SIGTERM); @@ -2023,198 +1885,152 @@ validate_image_directory (state *s, const char *path) } } - if (! validate_image_directory_cancelled_p) - { - if (s->debug_p) - fprintf (stderr, "%s: dismiss\n", blurb()); - warning_dialog_dismiss_cb (dialog, dialog); - } + if (vtc.timer_id) /* Remove the popup timer if it hasn't fired. */ + g_source_remove (vtc.timer_id); + + if (s->debug_p) + fprintf (stderr, "%s: dismiss\n", blurb()); + + if (! closed_p) + gtk_widget_destroy (dialog); FAIL: if (*err) { - sprintf (buf, _("Warning:\n\n%s\n"), err); - warning_dialog (s->toplevel_widget, buf, D_NONE, 1); - return False; + warning_dialog (s->window, _("Warning"), err); + return FALSE; } - return True; + return TRUE; } -typedef struct { - state *state; - GtkFileSelection *widget; -} file_selection_data; - - - /* Called when the imageDirectory text field is edited directly (focus-out). */ G_MODULE_EXPORT gboolean image_text_pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; - GtkEntry *w = GTK_ENTRY (name_to_widget (s, "image_text")); - const char *path = gtk_entry_get_text (w); + GtkEntry *w = GTK_ENTRY (win->image_text); + const char *str = gtk_entry_get_text (w); + char *path = pathname_tilde (str, TRUE, TRUE); - if (p->image_directory && !strcmp(p->image_directory, path)) + if (s->debug_p) fprintf (stderr, "%s: imagedir text edited\n", blurb()); + + if (p->image_directory && strcmp(p->image_directory, path)) { + if (s->debug_p) + fprintf (stderr, "%s: imagedir validating \"%s\" -> \"%s\"\n", blurb(), + p->image_directory, path); if (! validate_image_directory (s, path)) - /* Don't save the bad new value into the preferences. */ - return FALSE; + { + /* Don't save the bad new value into the preferences. */ + free (path); + return GDK_EVENT_PROPAGATE; + } } - return pref_changed_event_cb (widget, event, user_data); + free (path); + pref_changed_event_cb (widget, event, user_data); + return GDK_EVENT_PROPAGATE; } -static void -store_image_directory (GtkWidget *button, gpointer user_data) +/* Run a modal file selector dialog. + Select a file, directory, or program. + Normalize the resultant path and store it into the string pointer. + Also update the text field with the new path. + Returns true if any changes made. + */ +gboolean +file_chooser (GtkWindow *parent, GtkEntry *entry, char **retP, + const char *title, gboolean verbose_p, + gboolean dir_p, gboolean program_p) { - file_selection_data *fsd = (file_selection_data *) user_data; - state *s = fsd->state; - GtkFileSelection *selector = fsd->widget; - saver_preferences *p = &s->prefs; - char *path = - normalize_directory (gtk_file_selection_get_filename (selector)); - - if (s->debug_p) - fprintf (stderr, "%s: selected \"%s\n", blurb(), path); - - if (! validate_image_directory (s, path)) - { - /* Don't save the bad new value into the preferences. */ - free (path); - return; - } - - if (p->image_directory && !strcmp(p->image_directory, path)) + gint res; + gboolean changed_p = FALSE; + GtkWidget *dialog = + gtk_file_chooser_dialog_new (title, parent, + (dir_p + ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + : GTK_FILE_CHOOSER_ACTION_OPEN), + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Select"), GTK_RESPONSE_ACCEPT, + NULL); + const char *old = gtk_entry_get_text (entry); /* not *retP */ + + if (*old) { - free (path); - return; /* no change */ - } - - if (p->image_directory) free (p->image_directory); - p->image_directory = path; - - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "image_text")), - (p->image_directory ? p->image_directory : "")); - demo_write_init_file (s, p); -} - - -static void -store_text_file (GtkWidget *button, gpointer user_data) -{ - file_selection_data *fsd = (file_selection_data *) user_data; - state *s = fsd->state; - GtkFileSelection *selector = fsd->widget; - GtkWidget *top = s->toplevel_widget; - saver_preferences *p = &s->prefs; - char *path = - normalize_directory (gtk_file_selection_get_filename (selector)); + char *p2 = pathname_tilde (old, FALSE, dir_p); + GFile *gf; - if (p->text_file && !strcmp(p->text_file, path)) - { - free (path); - return; /* no change */ - } + /* If it's a command line and it begins with an absolute path, + default to that file and its directory. */ + if (program_p && (*p2 == '/' || *p2 == '~')) + { + char *s = strpbrk (p2, " \t\r\n"); + if (s) *s = 0; + program_p = FALSE; + } - if (!file_p (path)) - { - char b[255]; - sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path); - warning_dialog (GTK_WIDGET (top), b, D_NONE, 100); - free (path); - return; + gf = g_file_new_for_path (p2); + if (! program_p) + { + gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog), gf, NULL); + if (verbose_p) + fprintf (stderr, "%s: chooser: default \"%s\"\n", blurb(), p2); + } + free (p2); + g_object_unref (gf); } - if (p->text_file) free (p->text_file); - p->text_file = path; - - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_file_entry")), - (p->text_file ? p->text_file : "")); - demo_write_init_file (s, p); -} - - -static void -store_text_program (GtkWidget *button, gpointer user_data) -{ - file_selection_data *fsd = (file_selection_data *) user_data; - state *s = fsd->state; - GtkFileSelection *selector = fsd->widget; - /*GtkWidget *top = s->toplevel_widget;*/ - saver_preferences *p = &s->prefs; - char *path = - normalize_directory (gtk_file_selection_get_filename (selector)); - - if (p->text_program && !strcmp(p->text_program, path)) + res = gtk_dialog_run (GTK_DIALOG (dialog)); + if (res == GTK_RESPONSE_ACCEPT) { - free (path); - return; /* no change */ - } + GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog); + char *str = gtk_file_chooser_get_filename (chooser); + char *path = pathname_tilde (str, TRUE, dir_p); + g_free (str); -# if 0 - if (!file_p (path)) - { - char b[255]; - sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path); - warning_dialog (GTK_WIDGET (top), b, D_NONE, 100); - return; + if (*retP && !strcmp (*retP, path)) + { + if (verbose_p) + fprintf (stderr, "%s: chooser: unchanged\n", blurb()); + free (path); /* no change */ + } + else if (dir_p && !directory_p (path)) + { + char b[255]; + sprintf (b, _("Directory does not exist: \"%.100s\"\n"), path); + warning_dialog (parent, _("Error"), b); + free (path); /* no change */ + } + else if (!dir_p && !file_p (path)) + { + char b[255]; + sprintf (b, _("File does not exist: \"%.100s\"\n"), path); + warning_dialog (parent, _("Error"), b); + free (path); /* no change */ + } + else + { + if (verbose_p) + fprintf (stderr, "%s: chooser: \"%s\" -> \"%s\n", + blurb(), *retP, path); + if (*retP) free (*retP); + *retP = path; + gtk_entry_set_text (entry, path); + changed_p = TRUE; + } } -# endif - - if (p->text_program) free (p->text_program); - p->text_program = path; - - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_program_entry")), - (p->text_program ? p->text_program : "")); - demo_write_init_file (s, p); -} - - - -/* "Cancel" button on any "Browse" file selector */ -static void -browse_any_dir_cancel (GtkWidget *button, gpointer user_data) -{ - file_selection_data *fsd = (file_selection_data *) user_data; - gtk_widget_hide (GTK_WIDGET (fsd->widget)); -} - -/* "OK" button on imageDirectory "Browse" file selector */ -static void -browse_image_dir_ok (GtkWidget *button, gpointer user_data) -{ - browse_any_dir_cancel (button, user_data); - store_image_directory (button, user_data); -} - -/* "OK" button on textProgram "Browse" file selector */ -static void -browse_text_file_ok (GtkWidget *button, gpointer user_data) -{ - browse_any_dir_cancel (button, user_data); - store_text_file (button, user_data); -} - -/* "OK" button on textProgram "Browse" file selector */ -static void -browse_text_program_ok (GtkWidget *button, gpointer user_data) -{ - browse_any_dir_cancel (button, user_data); - store_text_program (button, user_data); -} + else if (verbose_p) + fprintf (stderr, "%s: chooser: cancelled\n", blurb()); -/* Close (X) button on any "Browse" file selector */ -static void -browse_any_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - browse_any_dir_cancel (widget, user_data); + gtk_widget_destroy (dialog); + return changed_p; } @@ -2222,45 +2038,30 @@ browse_any_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data) G_MODULE_EXPORT void browse_image_dir_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; - static file_selection_data *fsd = 0; - - GtkFileSelection *selector = GTK_FILE_SELECTION( - gtk_file_selection_new ("Please select the image directory.")); - - if (!fsd) - fsd = (file_selection_data *) malloc (sizeof (*fsd)); - - fsd->widget = selector; - fsd->state = s; - - if (p->image_directory && *p->image_directory) + char *old = strdup (p->image_directory); + + if (s->debug_p) fprintf (stderr, "%s: imagedir browse button\n", blurb()); + if (file_chooser (GTK_WINDOW (win), + GTK_ENTRY (win->image_text), + &p->image_directory, + _("Please select the image directory."), + s->debug_p, TRUE, FALSE)) { - /* It has to end in a slash, I guess? */ - char *ss = (char *) malloc (strlen (p->image_directory) + 2); - strcpy (ss, p->image_directory); - if (ss[strlen(ss)-1] != '/') - strcat (ss, "/"); - gtk_file_selection_set_filename (selector, ss); - free (ss); + if (validate_image_directory (s, p->image_directory)) + demo_write_init_file (s, p); + else + { + /* Don't save the bad new value into the preferences. */ + free (p->image_directory); + p->image_directory = old; + old = 0; + } } - gtk_file_selection_hide_fileop_buttons (selector); - gtk_signal_connect (GTK_OBJECT (selector->ok_button), - "clicked", GTK_SIGNAL_FUNC (browse_image_dir_ok), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector->cancel_button), - "clicked", GTK_SIGNAL_FUNC (browse_any_dir_cancel), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector), "delete_event", - GTK_SIGNAL_FUNC (browse_any_dir_close), - (gpointer *) fsd); - - gtk_widget_set_sensitive (GTK_WIDGET (selector->file_list), False); - - gtk_window_set_modal (GTK_WINDOW (selector), True); - gtk_widget_show (GTK_WIDGET (selector)); + if (old) free (old); } @@ -2268,35 +2069,17 @@ browse_image_dir_cb (GtkButton *button, gpointer user_data) G_MODULE_EXPORT void browse_text_file_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; - static file_selection_data *fsd = 0; - - GtkFileSelection *selector = GTK_FILE_SELECTION( - gtk_file_selection_new ("Please select a text file.")); - - if (!fsd) - fsd = (file_selection_data *) malloc (sizeof (*fsd)); - - fsd->widget = selector; - fsd->state = s; - - if (p->text_file && *p->text_file) - gtk_file_selection_set_filename (selector, p->text_file); - - gtk_file_selection_hide_fileop_buttons (selector); - gtk_signal_connect (GTK_OBJECT (selector->ok_button), - "clicked", GTK_SIGNAL_FUNC (browse_text_file_ok), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector->cancel_button), - "clicked", GTK_SIGNAL_FUNC (browse_any_dir_cancel), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector), "delete_event", - GTK_SIGNAL_FUNC (browse_any_dir_close), - (gpointer *) fsd); - gtk_window_set_modal (GTK_WINDOW (selector), True); - gtk_widget_show (GTK_WIDGET (selector)); + if (s->debug_p) fprintf (stderr, "%s: textfile browse button\n", blurb()); + if (file_chooser (GTK_WINDOW (win), + GTK_ENTRY (win->text_file_entry), + &p->text_file, + _("Please select a text file."), + s->debug_p, FALSE, FALSE)) + demo_write_init_file (s, p); } @@ -2304,35 +2087,17 @@ browse_text_file_cb (GtkButton *button, gpointer user_data) G_MODULE_EXPORT void browse_text_program_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; saver_preferences *p = &s->prefs; - static file_selection_data *fsd = 0; - GtkFileSelection *selector = GTK_FILE_SELECTION( - gtk_file_selection_new ("Please select a text-generating program.")); - - if (!fsd) - fsd = (file_selection_data *) malloc (sizeof (*fsd)); - - fsd->widget = selector; - fsd->state = s; - - if (p->text_program && *p->text_program) - gtk_file_selection_set_filename (selector, p->text_program); - - gtk_file_selection_hide_fileop_buttons (selector); - gtk_signal_connect (GTK_OBJECT (selector->ok_button), - "clicked", GTK_SIGNAL_FUNC (browse_text_program_ok), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector->cancel_button), - "clicked", GTK_SIGNAL_FUNC (browse_any_dir_cancel), - (gpointer *) fsd); - gtk_signal_connect (GTK_OBJECT (selector), "delete_event", - GTK_SIGNAL_FUNC (browse_any_dir_close), - (gpointer *) fsd); - - gtk_window_set_modal (GTK_WINDOW (selector), True); - gtk_widget_show (GTK_WIDGET (selector)); + if (s->debug_p) fprintf (stderr, "%s: textprogram browse button\n", blurb()); + if (file_chooser (GTK_WINDOW (win), + GTK_ENTRY (win->text_program_entry), + &p->text_program, + _("Please select a text-generating program."), + s->debug_p, FALSE, TRUE)) + demo_write_init_file (s, p); } @@ -2340,6 +2105,11 @@ browse_text_program_cb (GtkButton *button, gpointer user_data) G_MODULE_EXPORT void preview_theme_cb (GtkWidget *w, gpointer user_data) { + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + + if (s->debug_p) fprintf (stderr, "%s: preview theme button\n", blurb()); + /* Settings button is disabled with --splash --splash so that we don't end up with two copies of xscreensaver-settings running. */ if (system ("xscreensaver-auth --splash --splash &") < 0) @@ -2351,120 +2121,47 @@ preview_theme_cb (GtkWidget *w, gpointer user_data) G_MODULE_EXPORT void settings_cb (GtkButton *button, gpointer user_data) { - state *s = global_state_kludge; /* I hate C so much... */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (user_data); + state *s = &win->state; + saver_preferences *p = &s->prefs; + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); int list_elt = selected_list_element (s); + if (s->debug_p) fprintf (stderr, "%s: settings button\n", blurb()); + populate_demo_window (s, list_elt); /* reset the widget */ populate_popup_window (s); /* create UI on popup window */ - gtk_widget_show (s->popup_widget); -} -static void -settings_sync_cmd_text (state *s) -{ - GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text")); - char *cmd_line = get_configurator_command_line (s->cdata, False); - gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); - gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line)); - free (cmd_line); -} + /* Pre-select the "Standard" page. */ + settings_std_cb (NULL, s->dialog); + settings_switch_page_cb (GTK_NOTEBOOK (dialog->opt_notebook), NULL, 0, + s->dialog); -/* The "Advanced" button on the settings dialog. */ -G_MODULE_EXPORT void -settings_adv_cb (GtkButton *button, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - GtkNotebook *notebook = - GTK_NOTEBOOK (name_to_widget (s, "opt_notebook")); + /* If there is no saved position for the dialog, position it to the + right of the main window. See also restore_window_position(), + which already ran at startup. */ + { + int win_x, win_y, dialog_x, dialog_y; + char dummy; + char *old = p->settings_geom; + + if (!old || !*old || + 4 != sscanf (old, " %d , %d %d , %d %c", + &win_x, &win_y, &dialog_x, &dialog_y, &dummy)) + win_x = win_y = dialog_x = dialog_y = -1; + + if (dialog_x <= 0 && dialog_y <= 0) + { + int win_w, win_h; + gtk_window_get_position (GTK_WINDOW (s->window), &win_x, &win_y); + gtk_window_get_size (GTK_WINDOW (s->window), &win_w, &win_h); + dialog_x = win_x + win_w + 8; + dialog_y = win_y; + gtk_window_move (GTK_WINDOW (s->dialog), dialog_x, dialog_y); + } + } - settings_sync_cmd_text (s); - gtk_notebook_set_page (notebook, 1); -} - -/* The "Standard" button on the settings dialog. */ -G_MODULE_EXPORT void -settings_std_cb (GtkButton *button, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - GtkNotebook *notebook = - GTK_NOTEBOOK (name_to_widget (s, "opt_notebook")); - - /* Re-create UI to reflect the in-progress command-line settings. */ - populate_popup_window (s); - - gtk_notebook_set_page (notebook, 0); -} - -/* The "Reset to Defaults" button on the settings dialog. */ -G_MODULE_EXPORT void -settings_reset_cb (GtkButton *button, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text")); - char *cmd_line = get_configurator_command_line (s->cdata, True); - gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); - gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line)); - free (cmd_line); - populate_popup_window (s); -} - -/* Called when "Advanced/Standard" buttons change the displayed page. */ -G_MODULE_EXPORT void -settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page, - gint page_num, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - GtkWidget *adv = name_to_widget (s, "adv_button"); - GtkWidget *std = name_to_widget (s, "std_button"); - - if (page_num == 0) - { - gtk_widget_show (adv); - gtk_widget_hide (std); - } - else if (page_num == 1) - { - gtk_widget_hide (adv); - gtk_widget_show (std); - } - else - abort(); -} - - -/* The "Cancel" button on the Settings dialog. */ -G_MODULE_EXPORT void -settings_cancel_cb (GtkButton *button, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - gtk_widget_hide (s->popup_widget); -} - -/* The "Ok" button on the Settings dialog. */ -G_MODULE_EXPORT void -settings_ok_cb (GtkButton *button, gpointer user_data) -{ - state *s = global_state_kludge; /* I hate C so much... */ - GtkNotebook *notebook = GTK_NOTEBOOK (name_to_widget (s, "opt_notebook")); - int page = gtk_notebook_get_current_page (notebook); - - if (page == 0) - /* Regenerate the command-line from the widget contents before saving. - But don't do this if we're looking at the command-line page already, - or we will blow away what they typed... */ - settings_sync_cmd_text (s); - - flush_popup_changes_and_save (s); - gtk_widget_hide (s->popup_widget); -} - -/* The "Close" (X) button on the Settings dialog. */ -static gboolean -wm_popup_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - state *s = (state *) data; - settings_cancel_cb (0, (gpointer) s); - return TRUE; + gtk_widget_show (GTK_WIDGET (s->dialog)); } @@ -2475,18 +2172,19 @@ wm_popup_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data) /* Returns the number of the last hack run by the server. */ static int -server_current_hack (void) +server_current_hack (state *s) { Atom type; int format; unsigned long nitems, bytesafter; unsigned char *dataP = 0; - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; int hack_number = -1; + if (!dpy) return hack_number; if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */ XA_SCREENSAVER_STATUS, - 0, 3, False, XA_INTEGER, + 0, 3, FALSE, XA_INTEGER, &type, &format, &nitems, &bytesafter, &dataP) == Success @@ -2510,13 +2208,14 @@ server_current_hack (void) static void scroll_to_current_hack (state *s) { + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); saver_preferences *p = &s->prefs; int hack_number = -1; if (p->mode == ONE_HACK) /* in "one" mode, use the one */ hack_number = p->selected_hack; if (hack_number < 0) /* otherwise, use the last-run */ - hack_number = server_current_hack (); + hack_number = server_current_hack (s); if (hack_number < 0) /* failing that, last "one mode" */ hack_number = p->selected_hack; if (hack_number < 0) /* failing that, newest hack. */ @@ -2541,8 +2240,8 @@ scroll_to_current_hack (state *s) if (hack_number >= 0 && hack_number < p->screenhacks_count) { int list_elt = s->hack_number_to_list_elt[hack_number]; - GtkWidget *list = name_to_widget (s, "list"); - force_list_select_item (s, list, list_elt, True); + GtkWidget *list = win->list; + force_list_select_item (s, list, list_elt, TRUE); populate_demo_window (s, list_elt); populate_popup_window (s); } @@ -2552,9 +2251,9 @@ scroll_to_current_hack (state *s) static void populate_hack_list (state *s) { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; saver_preferences *p = &s->prefs; - GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkTreeView *list = GTK_TREE_VIEW (XSCREENSAVER_WINDOW (s->window)->list); GtkListStore *model; GtkTreeSelection *selection; GtkCellRenderer *ren; @@ -2620,16 +2319,15 @@ populate_hack_list (state *s) (but don't actually make it be insensitive, since we still want to be able to click on it.) */ - GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (list)); - GdkColor *fg = &style->fg[GTK_STATE_INSENSITIVE]; - /* GdkColor *bg = &style->bg[GTK_STATE_INSENSITIVE]; */ + GtkStyleContext *c = + gtk_widget_get_style_context (GTK_WIDGET (list)); + GdkRGBA fg; char *buf = (char *) malloc (strlen (pretty_name) + 100); - - sprintf (buf, "%s", - fg->red >> 8, fg->green >> 8, fg->blue >> 8, - /* bg->red >> 8, bg->green >> 8, bg->blue >> 8, */ + gtk_style_context_get_color (c, GTK_STATE_FLAG_INSENSITIVE, &fg); + sprintf (buf, "%s", + (unsigned int) (0xFF * fg.red), + (unsigned int) (0xFF * fg.green), + (unsigned int) (0xFF * fg.blue), pretty_name); free (pretty_name); pretty_name = buf; @@ -2644,9 +2342,11 @@ populate_hack_list (state *s) } } + static void update_list_sensitivity (state *s) { + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); saver_preferences *p = &s->prefs; Bool sensitive = (p->mode == RANDOM_HACKS || p->mode == RANDOM_HACKS_SAME || @@ -2655,15 +2355,12 @@ update_list_sensitivity (state *s) p->mode == RANDOM_HACKS_SAME); Bool blankable = (p->mode != DONT_BLANK); - GtkWidget *scroller = name_to_widget (s, "scroller"); - GtkWidget *buttons = name_to_widget (s, "next_prev_hbox"); - GtkWidget *blanker = name_to_widget (s, "blanking_table"); - GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list")); + GtkTreeView *list = GTK_TREE_VIEW (win->list); GtkTreeViewColumn *use = gtk_tree_view_get_column (list, COL_ENABLED); - gtk_widget_set_sensitive (GTK_WIDGET (scroller), sensitive); - gtk_widget_set_sensitive (GTK_WIDGET (buttons), sensitive); - gtk_widget_set_sensitive (GTK_WIDGET (blanker), blankable); + gtk_widget_set_sensitive (GTK_WIDGET (win->scroller), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (win->next_prev_hbox), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (win->blanking_table), blankable); gtk_tree_view_column_set_visible (use, checkable); } @@ -2671,18 +2368,16 @@ update_list_sensitivity (state *s) static void populate_prefs_page (state *s) { - Display *dpy = GDK_DISPLAY(); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + Display *dpy = s->dpy; saver_preferences *p = &s->prefs; - Bool can_lock_p = True; + Bool can_lock_p = TRUE; - /* Disable all the "lock" controls if locking support was not provided - at compile-time, or if running on MacOS. */ -# if defined(NO_LOCKING) || defined(__APPLE__) - can_lock_p = False; +# ifdef NO_LOCKING + can_lock_p = FALSE; # endif - /* If there is only one screen, the mode menu contains "random" but not "random-same". */ @@ -2701,108 +2396,99 @@ populate_prefs_page (state *s) # undef THROTTLE # define FMT_MINUTES(NAME,N) \ - gtk_spin_button_set_value (GTK_SPIN_BUTTON (name_to_widget (s, (NAME))), (double)((N) + 59) / (60 * 1000)) - + gtk_spin_button_set_value (GTK_SPIN_BUTTON (win->NAME), \ + (double) ((N) + 59) / (60 * 1000)) # define FMT_SECONDS(NAME,N) \ - gtk_spin_button_set_value (GTK_SPIN_BUTTON (name_to_widget (s, (NAME))), (double)((N) / 1000)) - - FMT_MINUTES ("timeout_spinbutton", p->timeout); - FMT_MINUTES ("cycle_spinbutton", p->cycle); - FMT_MINUTES ("lock_spinbutton", p->lock_timeout); - FMT_MINUTES ("dpms_standby_spinbutton", p->dpms_standby); - FMT_MINUTES ("dpms_suspend_spinbutton", p->dpms_suspend); - FMT_MINUTES ("dpms_off_spinbutton", p->dpms_off); - FMT_SECONDS ("fade_spinbutton", p->fade_seconds); - + gtk_spin_button_set_value (GTK_SPIN_BUTTON (win->NAME), \ + (double) ((N) / 1000)) + + FMT_MINUTES (timeout_spinbutton, p->timeout); + FMT_MINUTES (cycle_spinbutton, p->cycle); + FMT_MINUTES (lock_spinbutton, p->lock_timeout); + FMT_MINUTES (dpms_standby_spinbutton, p->dpms_standby); + FMT_MINUTES (dpms_suspend_spinbutton, p->dpms_suspend); + FMT_MINUTES (dpms_off_spinbutton, p->dpms_off); + FMT_SECONDS (fade_spinbutton, p->fade_seconds); # undef FMT_MINUTES # undef FMT_SECONDS # define TOGGLE_ACTIVE(NAME,ACTIVEP) \ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (name_to_widget (s,(NAME))),\ - (ACTIVEP)) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (win->NAME), (ACTIVEP)) - TOGGLE_ACTIVE ("lock_button", p->lock_p); -#if 0 - TOGGLE_ACTIVE ("verbose_button", p->verbose_p); - TOGGLE_ACTIVE ("splash_button", p->splash_p); -#endif - TOGGLE_ACTIVE ("dpms_button", p->dpms_enabled_p); - TOGGLE_ACTIVE ("dpms_quickoff_button", p->dpms_quickoff_p); - TOGGLE_ACTIVE ("grab_desk_button", p->grab_desktop_p); - TOGGLE_ACTIVE ("grab_video_button", p->grab_video_p); - TOGGLE_ACTIVE ("grab_image_button", p->random_image_p); - TOGGLE_ACTIVE ("fade_button", p->fade_p); - TOGGLE_ACTIVE ("unfade_button", p->unfade_p); + TOGGLE_ACTIVE (lock_button, p->lock_p); + TOGGLE_ACTIVE (dpms_button, p->dpms_enabled_p); + TOGGLE_ACTIVE (dpms_quickoff_button, p->dpms_quickoff_p); + TOGGLE_ACTIVE (grab_desk_button, p->grab_desktop_p); + TOGGLE_ACTIVE (grab_video_button, p->grab_video_p); + TOGGLE_ACTIVE (grab_image_button, p->random_image_p); + TOGGLE_ACTIVE (fade_button, p->fade_p); + TOGGLE_ACTIVE (unfade_button, p->unfade_p); switch (p->tmode) { - case TEXT_LITERAL: TOGGLE_ACTIVE ("text_radio", True); break; - case TEXT_FILE: TOGGLE_ACTIVE ("text_file_radio", True); break; - case TEXT_PROGRAM: TOGGLE_ACTIVE ("text_program_radio", True); break; - case TEXT_URL: TOGGLE_ACTIVE ("text_url_radio", True); break; - default: TOGGLE_ACTIVE ("text_host_radio", True); break; + case TEXT_LITERAL: TOGGLE_ACTIVE (text_radio, TRUE); break; + case TEXT_FILE: TOGGLE_ACTIVE (text_file_radio, TRUE); break; + case TEXT_PROGRAM: TOGGLE_ACTIVE (text_program_radio, TRUE); break; + case TEXT_URL: TOGGLE_ACTIVE (text_url_radio, TRUE); break; + default: TOGGLE_ACTIVE (text_host_radio, TRUE); break; } # undef TOGGLE_ACTIVE - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "image_text")), + gtk_entry_set_text (GTK_ENTRY (win->image_text), (p->image_directory ? p->image_directory : "")); - gtk_widget_set_sensitive (name_to_widget (s, "image_text"), - p->random_image_p); - gtk_widget_set_sensitive (name_to_widget (s, "image_browse_button"), + gtk_widget_set_sensitive (win->image_text, p->random_image_p); + gtk_widget_set_sensitive (win->image_browse_button, p->random_image_p); - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_entry")), + gtk_entry_set_text (GTK_ENTRY (win->text_entry), (p->text_literal ? p->text_literal : "")); - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_file_entry")), + gtk_entry_set_text (GTK_ENTRY (win->text_file_entry), (p->text_file ? p->text_file : "")); - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_program_entry")), + gtk_entry_set_text (GTK_ENTRY (win->text_program_entry), (p->text_program ? p->text_program : "")); - gtk_entry_set_text (GTK_ENTRY (name_to_widget (s, "text_url_entry")), + gtk_entry_set_text (GTK_ENTRY (win->text_url_entry), (p->text_url ? p->text_url : "")); - gtk_widget_set_sensitive (name_to_widget (s, "text_entry"), + gtk_widget_set_sensitive (win->text_entry, p->tmode == TEXT_LITERAL); - gtk_widget_set_sensitive (name_to_widget (s, "text_file_entry"), + gtk_widget_set_sensitive (win->text_file_entry, p->tmode == TEXT_FILE); - gtk_widget_set_sensitive (name_to_widget (s, "text_file_browse"), + gtk_widget_set_sensitive (win->text_file_browse, p->tmode == TEXT_FILE); - gtk_widget_set_sensitive (name_to_widget (s, "text_program_entry"), + gtk_widget_set_sensitive (win->text_program_entry, p->tmode == TEXT_PROGRAM); - gtk_widget_set_sensitive (name_to_widget (s, "text_program_browse"), + gtk_widget_set_sensitive (win->text_program_browse, p->tmode == TEXT_PROGRAM); - gtk_widget_set_sensitive (name_to_widget (s, "text_url_entry"), + gtk_widget_set_sensitive (win->text_url_entry, p->tmode == TEXT_URL); - /* Theme menu */ { - GtkComboBox *cbox = GTK_COMBO_BOX (name_to_widget (s, "theme_menu")); + GtkComboBox *cbox = GTK_COMBO_BOX (win->theme_menu); - /* Without this, pref_changed_cb gets called an exponentially-increasing - number of times on the themes menu, despite the call to - gtk_list_store_clear(). */ - static Bool done_once = False; - - if (cbox && !done_once) + if (cbox) { char *themes = get_string_resource (dpy, "themeNames", "ThemeNames"); - char *token = themes; - char *name, *name2, *last; + char *token = themes ? themes : strdup ("default"); + char *name, *last = 0; GtkListStore *model; GtkTreeIter iter; int i = 0; - done_once = True; - - g_object_get (G_OBJECT (cbox), "model", &model, NULL); - if (!model) abort(); - gtk_list_store_clear (model); + /* Bad things happen if we do these things more than once. */ + static Bool model_built_p = FALSE; + static Bool signal_connected_p = FALSE; - gtk_signal_connect (GTK_OBJECT (cbox), "changed", - GTK_SIGNAL_FUNC (pref_changed_cb), (gpointer) s); + if (! model_built_p) + { + g_object_get (G_OBJECT (cbox), "model", &model, NULL); + if (!model) abort(); + gtk_list_store_clear (model); + } while ((name = strtok_r (token, ",", &last))) { + char *name2; int L; token = 0; @@ -2814,22 +2500,33 @@ populate_prefs_page (state *s) name[L-1] == '\n')) name[--L] = 0; - gtk_list_store_append (model, &iter); - gtk_list_store_set (model, &iter, 0, name, -1); + if (! model_built_p) + { + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, 0, name, -1); + } name2 = theme_name_strip (name); - if (!strcmp (p->dialog_theme, name2)) + if (p->dialog_theme && name2 && !strcmp (p->dialog_theme, name2)) gtk_combo_box_set_active (cbox, i); free (name2); i++; } + + model_built_p = TRUE; + + if (! signal_connected_p) + { + g_signal_connect (G_OBJECT (cbox), "changed", + G_CALLBACK (pref_changed_cb), (gpointer) s); + signal_connected_p = TRUE; + } } } - /* Map the `saver_mode' enum to mode menu to values. */ { - GtkComboBox *opt = GTK_COMBO_BOX (name_to_widget (s, "mode_menu")); + GtkComboBox *opt = GTK_COMBO_BOX (win->mode_menu); int i; for (i = 0; i < countof(mode_menu_order); i++) @@ -2840,58 +2537,50 @@ populate_prefs_page (state *s) } { - Bool dpms_supported = False; - Display *dpy = GDK_DISPLAY(); + Bool dpms_supported = FALSE; + Display *dpy = s->dpy; #ifdef HAVE_DPMS_EXTENSION { int op = 0, event = 0, error = 0; - if (XQueryExtension (dpy, "DPMS", &op, &event, &error)) - dpms_supported = True; + if (dpy && XQueryExtension (dpy, "DPMS", &op, &event, &error)) + dpms_supported = TRUE; } #endif /* HAVE_DPMS_EXTENSION */ # define SENSITIZE(NAME,SENSITIVEP) \ - gtk_widget_set_sensitive (name_to_widget (s, (NAME)), (SENSITIVEP)) + gtk_widget_set_sensitive (win->NAME, (SENSITIVEP)) /* Blanking and Locking */ - SENSITIZE ("lock_button", can_lock_p); - SENSITIZE ("lock_spinbutton", can_lock_p && p->lock_p); - SENSITIZE ("lock_mlabel", can_lock_p && p->lock_p); + SENSITIZE (lock_button, can_lock_p); + SENSITIZE (lock_spinbutton, can_lock_p && p->lock_p); + SENSITIZE (lock_mlabel, can_lock_p && p->lock_p); /* DPMS */ - SENSITIZE ("dpms_frame", dpms_supported); - SENSITIZE ("dpms_button", dpms_supported); - - SENSITIZE ("dpms_standby_label", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_standby_mlabel", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_standby_spinbutton", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_suspend_label", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_suspend_mlabel", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_suspend_spinbutton", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_off_label", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_off_mlabel", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_off_spinbutton", dpms_supported && p->dpms_enabled_p); - SENSITIZE ("dpms_quickoff_button", dpms_supported); - - SENSITIZE ("fade_label", (p->fade_p || p->unfade_p)); - SENSITIZE ("fade_spinbutton", (p->fade_p || p->unfade_p)); + SENSITIZE (dpms_button, dpms_supported); + SENSITIZE (dpms_standby_label, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_standby_mlabel, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_standby_spinbutton, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_suspend_label, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_suspend_mlabel, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_suspend_spinbutton, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_off_label, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_off_mlabel, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_off_spinbutton, dpms_supported && p->dpms_enabled_p); + SENSITIZE (dpms_quickoff_button, dpms_supported); + + SENSITIZE (fade_label, (p->fade_p || p->unfade_p)); + SENSITIZE (fade_spinbutton, (p->fade_p || p->unfade_p)); # undef SENSITIZE - } -} - -/* Allow the documentation label to re-flow when the text is changed. - http://blog.borovsak.si/2009/05/wrapping-adn-resizing-gtklabel.html - */ -static void -cb_allocate (GtkWidget *label, GtkAllocation *allocation, gpointer data) -{ - gtk_widget_set_size_request (label, allocation->width - 8, -1); + if (!dpms_supported) + gtk_frame_set_label (GTK_FRAME (win->dpms_frame), + _("Display Power Management (not supported by this display)")); + } } @@ -2967,6 +2656,7 @@ anchorize (const char *url) } } + /* Quote the text as HTML and make URLs be clickable links. */ static char * @@ -3030,162 +2720,13 @@ hreffify (const char *in) } -/* Fill in the contents of the "Settings" dialog for the current hack. - It may or may not currently be visible. - */ -static void -populate_popup_window (state *s) -{ - GtkLabel *doc = GTK_LABEL (name_to_widget (s, "doc")); - char *doc_string = 0; - - g_signal_connect (G_OBJECT (doc), "size-allocate", - G_CALLBACK (cb_allocate), NULL); - - if (s->cdata) - { - free_conf_data (s->cdata); - s->cdata = 0; - } - - { - saver_preferences *p = &s->prefs; - int list_elt = selected_list_element (s); - int hack_number = (list_elt >= 0 && list_elt < s->list_count - ? s->list_elt_to_hack_number[list_elt] - : -1); - screenhack *hack = (hack_number >= 0 ? p->screenhacks[hack_number] : 0); - if (hack) - { - GtkWidget *parent = name_to_widget (s, "settings_vbox"); - GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text")); - const char *cmd_line = gtk_entry_get_text (GTK_ENTRY (cmd)); - s->cdata = load_configurator (cmd_line, s->debug_p); - if (s->cdata && s->cdata->widget) - gtk_box_pack_start (GTK_BOX (parent), s->cdata->widget, - TRUE, TRUE, 0); - - /* Make the pretty name on the tab boxes include the year. - */ - if (s->cdata && s->cdata->year) - { - Display *dpy = GDK_DISPLAY(); - GtkFrame *frame1 = GTK_FRAME (name_to_widget (s, "preview_frame")); - GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "opt_frame")); - GtkWidget *label1, *label2; - GtkStyle *style; - PangoFontDescription *font; - char *pretty_name = (hack->name - ? strdup (hack->name) - : make_hack_name (dpy, hack->command)); - char *s2 = (char *) malloc (strlen (pretty_name) + 10); - sprintf (s2, "%s (%d)", pretty_name, s->cdata->year); - free (pretty_name); - pretty_name = s2; - - gtk_frame_set_label (frame1, _(pretty_name)); - gtk_frame_set_label (frame2, _(pretty_name)); - - /* Make the labels be bold. Must be after gtk_frame_set_label. - You'd think you could specify this in "xscreensaver.ui"... - */ - label1 = gtk_frame_get_label_widget (frame1); - label2 = gtk_frame_get_label_widget (frame2); - - style = gtk_widget_get_style (label1); - font = pango_font_description_copy_static (style->font_desc); - pango_font_description_set_weight (font, PANGO_WEIGHT_BOLD); - - gtk_widget_modify_font (label1, font); - gtk_widget_modify_font (label2, font); - - pango_font_description_free (font); - free (pretty_name); - } - } - } - - doc_string = (s->cdata && s->cdata->description && *s->cdata->description - ? _(s->cdata->description) - : 0); - doc_string = hreffify (doc_string); - gtk_label_set_text (doc, (doc_string - ? doc_string - : _("No description available."))); - gtk_label_set_use_markup (doc, True); - - { - GtkWidget *w = name_to_widget (s, "dialog_vbox"); - gtk_widget_hide (w); - gtk_widget_unrealize (w); - gtk_widget_realize (w); - gtk_widget_show (w); - } - - /* Also set the documentation on the main window, below the preview. */ - { - GtkLabel *doc2 = GTK_LABEL (name_to_widget (s, "short_preview_label")); - GtkLabel *doc3 = GTK_LABEL (name_to_widget (s, "preview_author_label")); - char *s2 = 0; - char *s3 = 0; - -# if 0 - g_signal_connect (G_OBJECT (doc2), "size-allocate", - G_CALLBACK (cb_allocate), NULL); - g_signal_connect (G_OBJECT (doc3), "size-allocate", - G_CALLBACK (cb_allocate), NULL); -# endif - - if (doc_string) - { - /* Keep only the first paragraph, and the last line. - Omit everything in between. */ - char *second_para = strstr (doc_string, "\n\n"); - char *last_line = strrchr (doc_string, '\n'); - s2 = strdup (doc_string); - if (second_para) - s2[second_para - doc_string] = 0; - if (last_line) - s3 = strdup (last_line + 1); - } - - gtk_label_set_text (doc2, (s2 - ? _(s2) - : _("No description available."))); - gtk_label_set_text (doc3, (s3 ? _(s3) : "")); - if (s2) free (s2); - if (s3) free (s3); - } - - if (doc_string) - free (doc_string); -} - - -static void -sensitize_demo_widgets (state *s, Bool sensitive_p) -{ - const char *names[] = { "demo", "settings", - "cmd_label", "cmd_text", "manual", - "visual", "visual_combo" }; - int i; - for (i = 0; i < countof(names); i++) - { - GtkWidget *w = name_to_widget (s, names[i]); - gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p); - } -} - - static void sensitize_menu_items (state *s, Bool force_p) { - static Bool running_p = False; + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + static Bool running_p = FALSE; static time_t last_checked = 0; time_t now = time ((time_t *) 0); - const char *names[] = { "activate_action", "lock_action", "kill_action", - /* "demo" */ }; - int i; if (force_p || now > last_checked + 10) /* check every 10 seconds */ { @@ -3193,81 +2734,49 @@ sensitize_menu_items (state *s, Bool force_p) last_checked = time ((time_t *) 0); } - for (i = 0; i < countof(names); i++) - { - GtkAction *a = GTK_ACTION (gtk_builder_get_object (s->gtk_ui, names[i])); - gtk_action_set_sensitive (a, running_p); - } -} - - -/* When the File menu is de-posted after a "Restart Daemon" command, - the window underneath doesn't repaint for some reason. I guess this - is a bug in exposure handling in GTK or GDK. This works around it. - */ -static void -force_dialog_repaint (state *s) -{ -#if 1 - /* Tell GDK to invalidate and repaint the whole window. - */ - GdkWindow *w = GET_WINDOW (s->toplevel_widget); - GdkRegion *region = gdk_region_new (); - GdkRectangle rect; - rect.x = rect.y = 0; - rect.width = rect.height = 32767; - gdk_region_union_with_rect (region, &rect); - gdk_window_invalidate_region (w, region, True); - gdk_region_destroy (region); - gdk_window_process_updates (w, True); -#else - /* Force the server to send an exposure event by creating and then - destroying a window as a child of the top level shell. - */ - Display *dpy = GDK_DISPLAY(); - Window parent = GDK_WINDOW_XWINDOW (s->toplevel_widget->window); - Window w; - XWindowAttributes xgwa; - XGetWindowAttributes (dpy, parent, &xgwa); - w = XCreateSimpleWindow (dpy, parent, 0, 0, xgwa.width, xgwa.height, 0,0,0); - XMapRaised (dpy, w); - XDestroyWindow (dpy, w); - XSync (dpy, False); -#endif + gtk_widget_set_sensitive (win->activate_menuitem, running_p); + gtk_widget_set_sensitive (win->lock_menuitem, running_p); + gtk_widget_set_sensitive (win->kill_menuitem, running_p); } -/* Fill in the contents of the main page. +/* Fill in the contents of the main window, and a few things on the + settings dialog. */ static void populate_demo_window (state *s, int list_elt) { - Display *dpy = GDK_DISPLAY(); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); + Display *dpy = s->dpy; saver_preferences *p = &s->prefs; screenhack *hack; char *pretty_name; - GtkFrame *frame1 = GTK_FRAME (name_to_widget (s, "preview_frame")); - GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "opt_frame")); - GtkEntry *cmd = GTK_ENTRY (name_to_widget (s, "cmd_text")); - GtkComboBoxEntry *vis = GTK_COMBO_BOX_ENTRY (name_to_widget (s, "visual_combo")); - GtkWidget *list = GTK_WIDGET (name_to_widget (s, "list")); + GtkFrame *frame1 = GTK_FRAME (win->preview_frame); + GtkFrame *frame2 = dialog ? GTK_FRAME (dialog->opt_frame) : 0; + GtkEntry *cmd = dialog ? GTK_ENTRY (dialog->cmd_text) : 0; + GtkComboBox *vis = dialog ? GTK_COMBO_BOX (dialog->visual_combo) : 0; + GtkWidget *list = GTK_WIDGET (win->list); /* Enforce a minimum size on the preview pane. */ - int dw = DisplayWidth (dpy, 0); - int dh = DisplayHeight (dpy, 0); - int minw, minh; -# define TRY(W) do { \ - minw = (W); minh = minw * 9/16; \ - if (dw > minw * 1.5 && dh > minh * 1.5) \ - gtk_widget_set_size_request (GTK_WIDGET (frame1), minw, minh); \ - } while(0) - TRY (300); - TRY (400); - TRY (480); - TRY (640); - TRY (800); -/* TRY (960); */ + if (dpy) + { + int dw = DisplayWidth (dpy, 0); + int dh = DisplayHeight (dpy, 0); + int minw, minh; + # define TRY(W) do { \ + minw = (W); minh = minw * 9/16; \ + if (dw > minw * 1.5 && dh > minh * 1.5) \ + gtk_widget_set_size_request (GTK_WIDGET (frame1), minw, minh); \ + } while(0) + TRY (300); + TRY (400); + TRY (480); + TRY (640); + TRY (800); + /* TRY (960); */ # undef TRY + } if (p->mode == BLANK_ONLY) { @@ -3303,27 +2812,34 @@ populate_demo_window (state *s, int list_elt) if (!pretty_name) pretty_name = strdup (_("Preview")); - gtk_frame_set_label (frame1, _(pretty_name)); - gtk_frame_set_label (frame2, _(pretty_name)); + if (dialog->unedited_cmdline) free (dialog->unedited_cmdline); + dialog->unedited_cmdline = strdup (hack ? hack->command : ""); - gtk_entry_set_text (cmd, (hack ? hack->command : "")); - gtk_entry_set_position (cmd, 0); + gtk_frame_set_label (frame1, _(pretty_name)); + if (frame2) + gtk_frame_set_label (frame2, _(pretty_name)); + if (cmd) + gtk_entry_set_text (cmd, dialog->unedited_cmdline); { char title[255]; sprintf (title, _("%s: %.100s Settings"), progclass, (pretty_name ? pretty_name : "???")); - gtk_window_set_title (GTK_WINDOW (s->popup_widget), title); + gtk_window_set_title (GTK_WINDOW (s->window), title); + if (s->dialog) + gtk_window_set_title (GTK_WINDOW (s->dialog), title); } - gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (vis))), - (hack - ? (hack->visual && *hack->visual - ? hack->visual - : _("Any")) - : "")); + /* Fill in the Visual combo-box */ + if (vis) + gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (vis))), + (hack + ? (hack->visual && *hack->visual + ? hack->visual + : _("Any")) + : "")); - sensitize_demo_widgets (s, (hack ? True : False)); + sensitize_demo_widgets (s, (hack ? TRUE : FALSE)); if (pretty_name) free (pretty_name); @@ -3336,19 +2852,7 @@ populate_demo_window (state *s, int list_elt) static void widget_deleter (GtkWidget *widget, gpointer data) { - /* #### Well, I want to destroy these widgets, but if I do that, they get - referenced again, and eventually I get a SEGV. So instead of - destroying them, I'll just hide them, and leak a bunch of memory - every time the disk file changes. Go go go Gtk! - - #### Ok, that's a lie, I get a crash even if I just hide the widget - and don't ever delete it. Fuck! - */ -#if 0 gtk_widget_destroy (widget); -#else - gtk_widget_hide (widget); -#endif } @@ -3372,7 +2876,7 @@ sort_hack_cmp (const void *a, const void *b) static void initialize_sort_map (state *s) { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; saver_preferences *p = &s->prefs; int i, j; @@ -3458,13 +2962,14 @@ initialize_sort_map (state *s) static int maybe_reload_init_file (state *s) { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; saver_preferences *p = &s->prefs; + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); int status = 0; - static Bool reentrant_lock = False; + static Bool reentrant_lock = FALSE; if (reentrant_lock) return 0; - reentrant_lock = True; + reentrant_lock = TRUE; if (init_file_changed_p (p)) { @@ -3475,21 +2980,18 @@ maybe_reload_init_file (state *s) if (!f || !*f) return 0; b = (char *) malloc (strlen(f) + 1024); - sprintf (b, - _("Warning:\n\n" - "file \"%s\" has changed, reloading.\n"), - f); - warning_dialog (s->toplevel_widget, b, D_NONE, 100); + sprintf (b, _("file \"%s\" has changed, reloading.\n"), f); + warning_dialog (s->window, _("Warning"), b); free (b); load_init_file (dpy, p); initialize_sort_map (s); list_elt = selected_list_element (s); - list = name_to_widget (s, "list"); + list = win->list; gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL); populate_hack_list (s); - force_list_select_item (s, list, list_elt, True); + force_list_select_item (s, list, list_elt, TRUE); populate_prefs_page (s); populate_demo_window (s, list_elt); populate_popup_window (s); @@ -3498,7 +3000,7 @@ maybe_reload_init_file (state *s) status = 1; } - reentrant_lock = False; + reentrant_lock = FALSE; return status; } @@ -3509,59 +3011,44 @@ maybe_reload_init_file (state *s) static Visual *get_best_gl_visual (state *); static GdkVisual * -x_visual_to_gdk_visual (Visual *xv) +x_visual_to_gdk_visual (GdkWindow *win, Visual *xv) { - GList *gvs = gdk_list_visuals(); - if (!xv) return gdk_visual_get_system(); - for (; gvs; gvs = gvs->next) + if (xv) { - GdkVisual *gv = (GdkVisual *) gvs->data; - if (xv == GDK_VISUAL_XVISUAL (gv)) - return gv; + GdkScreen *screen = gdk_window_get_screen (win); + GList *gvs = gdk_screen_list_visuals (screen); + /* This list is sometimes NULL, not even the default visual! */ + for (; gvs; gvs = gvs->next) + { + GdkVisual *gv = (GdkVisual *) gvs->data; + if (xv == GDK_VISUAL_XVISUAL (gv)) + return gv; + } } - fprintf (stderr, "%s: couldn't convert X Visual 0x%lx to a GdkVisual\n", - blurb(), (unsigned long) xv->visualid); - abort(); + return 0; } + static void clear_preview_window (state *s) { - GtkWidget *p; - GdkWindow *window; - GtkStyle *style; - - if (!s->toplevel_widget) return; /* very early */ - p = name_to_widget (s, "preview"); - window = GET_WINDOW (p); - - if (!window) return; - - /* Flush the widget background down into the window, in case a subproc - has changed it. */ - style = gtk_widget_get_style (p); - gdk_window_set_background (window, &style->bg[GTK_STATE_NORMAL]); - gdk_window_clear (window); - - { - int list_elt = selected_list_element (s); - int hack_number = (list_elt >= 0 - ? s->list_elt_to_hack_number[list_elt] - : -1); - Bool available_p = (hack_number >= 0 - ? s->hacks_available_p [hack_number] - : True); - Bool nothing_p = (s->total_available < 5); - - GtkWidget *notebook = name_to_widget (s, "preview_notebook"); - gtk_notebook_set_page (GTK_NOTEBOOK (notebook), - (s->running_preview_error_p - ? (available_p ? 1 : - nothing_p ? 3 : 2) - : 0)); - } - - gdk_flush (); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + int list_elt = selected_list_element (s); + int hack_number = (list_elt >= 0 + ? s->list_elt_to_hack_number[list_elt] + : -1); + Bool available_p = (hack_number >= 0 + ? s->hacks_available_p [hack_number] + : TRUE); + Bool nothing_p = (s->total_available < 5); + + GtkWidget *notebook = win->preview_notebook; + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), + (!s->running_preview_error_p ? 0 : /* ok */ + nothing_p ? 3 : /* no hacks installed */ + !available_p ? 2 : /* hack not installed */ + s->wayland_p ? 4 : /* fucking wayland */ + 1)); /* preview failed */ } @@ -3573,17 +3060,19 @@ reset_preview_window (state *s) it's best to just always destroy and recreate the preview window when changing hacks, instead of always trying to reuse the same one? */ - GtkWidget *pr = name_to_widget (s, "preview"); - if (GET_REALIZED (pr)) + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkWidget *pr = win->preview; + if (s->dpy && !s->wayland_p && gtk_widget_get_realized (pr)) { - GdkWindow *window = GET_WINDOW (pr); - Window oid = (window ? GDK_WINDOW_XWINDOW (window) : 0); + GdkWindow *window = gtk_widget_get_window (pr); + Window oid = (window ? gdk_x11_window_get_xid (window) : 0); Window id; gtk_widget_hide (pr); gtk_widget_unrealize (pr); + gtk_widget_set_has_window (pr, TRUE); gtk_widget_realize (pr); gtk_widget_show (pr); - id = (window ? GDK_WINDOW_XWINDOW (window) : 0); + id = (window ? gdk_x11_window_get_xid (window) : 0); if (s->debug_p) fprintf (stderr, "%s: window id 0x%X -> 0x%X\n", blurb(), (unsigned int) oid, @@ -3592,59 +3081,47 @@ reset_preview_window (state *s) } +/* Make the preview widget use the best GL visual. + We just always use that one rather than switching. + */ static void fix_preview_visual (state *s) { - GtkWidget *widget = name_to_widget (s, "preview"); + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); Visual *xvisual = get_best_gl_visual (s); - GdkVisual *visual = x_visual_to_gdk_visual (xvisual); - GdkVisual *dvisual = gdk_visual_get_system(); - GdkColormap *cmap = (visual == dvisual - ? gdk_colormap_get_system () - : gdk_colormap_new (visual, False)); + GtkWidget *widget = win->preview; + GdkWindow *gwindow = gtk_widget_get_window (GTK_WIDGET (win)); + GdkScreen *gscreen = gdk_window_get_screen (gwindow); + GdkVisual *gvisual1 = gdk_screen_get_system_visual (gscreen); + GdkVisual *gvisual2 = x_visual_to_gdk_visual (gwindow, xvisual); + + if (! gvisual2) + { + gvisual2 = gvisual1; + if (s->debug_p) + fprintf (stderr, "%s: couldn't convert X Visual 0x%lx to a GdkVisual;" + " winging it.\n", + blurb(), (unsigned long) xvisual->visualid); + } if (s->debug_p) fprintf (stderr, "%s: using %s visual 0x%lx\n", blurb(), - (visual == dvisual ? "default" : "non-default"), + (gvisual1 == gvisual2 ? "default" : "non-default"), (xvisual ? (unsigned long) xvisual->visualid : 0L)); - if (!GET_REALIZED (widget) || - gtk_widget_get_visual (widget) != visual) + if (!gtk_widget_get_realized (widget) || + gtk_widget_get_visual (widget) != gvisual2) { gtk_widget_unrealize (widget); - gtk_widget_set_visual (widget, visual); - gtk_widget_set_colormap (widget, cmap); + gtk_widget_set_has_window (widget, TRUE); + gtk_widget_set_visual (widget, gvisual2); gtk_widget_realize (widget); } - /* Set the Widget colors to be white-on-black. */ - { - GdkWindow *window = GET_WINDOW (widget); - GtkStyle *style = gtk_style_copy (gtk_widget_get_style (widget)); - GdkColormap *cmap = gtk_widget_get_colormap (widget); - GdkColor *fg = &style->fg[GTK_STATE_NORMAL]; - GdkColor *bg = &style->bg[GTK_STATE_NORMAL]; - GdkGC *fgc = gdk_gc_new(window); - GdkGC *bgc = gdk_gc_new(window); - if (!gdk_color_white (cmap, fg)) abort(); - if (!gdk_color_black (cmap, bg)) abort(); - gdk_gc_set_foreground (fgc, fg); - gdk_gc_set_background (fgc, bg); - gdk_gc_set_foreground (bgc, bg); - gdk_gc_set_background (bgc, fg); - style->fg_gc[GTK_STATE_NORMAL] = fgc; - style->bg_gc[GTK_STATE_NORMAL] = fgc; - gtk_widget_set_style (widget, style); - - /* For debugging purposes, put a title on the window (so that - it can be easily found in the output of "xwininfo -tree".) - */ - gdk_window_set_title (window, "Preview"); - } - gtk_widget_show (widget); } + /* Subprocesses */ @@ -3699,7 +3176,7 @@ reap_zombies (state *s) static Visual * get_best_gl_visual (state *s) { - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; pid_t forked; int fds [2]; int in, out; @@ -3804,18 +3281,17 @@ get_best_gl_visual (state *s) abort(); } - static void kill_preview_subproc (state *s, Bool reset_p) { - s->running_preview_error_p = False; + s->running_preview_error_p = FALSE; reap_zombies (s); clear_preview_window (s); if (s->subproc_check_timer_id) { - gtk_timeout_remove (s->subproc_check_timer_id); + g_source_remove (s->subproc_check_timer_id); s->subproc_check_timer_id = 0; s->subproc_check_countdown = 0; } @@ -3871,30 +3347,33 @@ kill_preview_subproc (state *s, Bool reset_p) static void launch_preview_subproc (state *s) { + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); saver_preferences *p = &s->prefs; Window id; char *new_cmd = 0; pid_t forked; const char *cmd = s->desired_preview_cmd; - GtkWidget *pr = name_to_widget (s, "preview"); + GtkWidget *pr = win->preview; GdkWindow *window; reset_preview_window (s); - window = GET_WINDOW (pr); + window = gtk_widget_get_window (pr); - s->running_preview_error_p = False; + s->running_preview_error_p = FALSE; if (s->preview_suppressed_p) { - kill_preview_subproc (s, False); + kill_preview_subproc (s, FALSE); goto DONE; } new_cmd = malloc (strlen (cmd) + 40); - id = (window ? GDK_WINDOW_XWINDOW (window) : 0); + id = (window && !s->wayland_p + ? gdk_x11_window_get_xid (window) + : 0); if (id == 0) { /* No window id? No command to run. */ @@ -3904,19 +3383,19 @@ launch_preview_subproc (state *s) else { /* We do this instead of relying on $XSCREENSAVER_WINDOW specifically - so that third-party savers that don't implement -window-id will fail: + so that third-party savers that don't implement --window-id will fail: otherwise we might have full-screen windows popping up when we were just trying to get a preview thumbnail. */ strcpy (new_cmd, cmd); - sprintf (new_cmd + strlen (new_cmd), " -window-id 0x%X", + sprintf (new_cmd + strlen (new_cmd), " --window-id 0x%X", (unsigned int) id); } - kill_preview_subproc (s, False); + kill_preview_subproc (s, FALSE); if (! new_cmd) { - s->running_preview_error_p = True; + s->running_preview_error_p = TRUE; clear_preview_window (s); goto DONE; } @@ -3928,13 +3407,13 @@ launch_preview_subproc (state *s) char buf[255]; sprintf (buf, "%s: couldn't fork", blurb()); perror (buf); - s->running_preview_error_p = True; + s->running_preview_error_p = TRUE; goto DONE; break; } case 0: { - close (ConnectionNumber (GDK_DISPLAY())); + close (ConnectionNumber (s->dpy)); hack_subproc_environment (id, s->debug_p); @@ -3993,8 +3472,8 @@ hack_environment (state *s) ""; # endif - Display *dpy = GDK_DISPLAY(); - const char *odpy = DisplayString (dpy); + Display *dpy = s->dpy; + const char *odpy = dpy ? DisplayString (dpy) : ":0.0"; char *ndpy = (char *) malloc(strlen(odpy) + 20); strcpy (ndpy, "DISPLAY="); strcat (ndpy, odpy); @@ -4033,7 +3512,7 @@ hack_subproc_environment (Window preview_window_id, Bool debug_p) { /* Store a window ID in $XSCREENSAVER_WINDOW -- this isn't strictly necessary yet, but it will make programs work if we had invoked - them with "-root" and not with "-window-id" -- which, of course, + them with "--root" and not with "--window-id" -- which, of course, doesn't happen. */ char *nssw = (char *) malloc (40); @@ -4051,6 +3530,7 @@ hack_subproc_environment (Window preview_window_id, Bool debug_p) } + /* Called from a timer: Launches the currently-chosen subprocess, if it's not already running. If there's a different process running, kills it. @@ -4060,7 +3540,7 @@ update_subproc_timer (gpointer data) { state *s = (state *) data; if (! s->desired_preview_cmd) - kill_preview_subproc (s, True); + kill_preview_subproc (s, TRUE); else if (!s->running_preview_cmd || !!strcmp (s->desired_preview_cmd, s->running_preview_cmd)) launch_preview_subproc (s); @@ -4069,13 +3549,6 @@ update_subproc_timer (gpointer data) return FALSE; /* do not re-execute timer */ } -static int -settings_timer (gpointer data) -{ - settings_cb (0, 0); - return FALSE; /* Only run timer once */ -} - /* Call this when you think you might want a preview process running. It will set a timer that will actually launch that program a second @@ -4099,8 +3572,8 @@ schedule_preview (state *s, const char *cmd) s->desired_preview_cmd = (cmd ? strdup (cmd) : 0); if (s->subproc_timer_id) - gtk_timeout_remove (s->subproc_timer_id); - s->subproc_timer_id = gtk_timeout_add (delay, update_subproc_timer, s); + g_source_remove (s->subproc_timer_id); + s->subproc_timer_id = g_timeout_add (delay, update_subproc_timer, s); } @@ -4111,12 +3584,12 @@ static int check_subproc_timer (gpointer data) { state *s = (state *) data; - Bool again_p = True; + Bool again_p = TRUE; if (s->running_preview_error_p || /* already dead */ s->running_preview_pid <= 0) { - again_p = False; + again_p = FALSE; } else { @@ -4124,7 +3597,7 @@ check_subproc_timer (gpointer data) reap_zombies (s); status = kill (s->running_preview_pid, 0); if (status < 0 && errno == ESRCH) - s->running_preview_error_p = True; + s->running_preview_error_p = TRUE; if (s->debug_p) { @@ -4138,7 +3611,7 @@ check_subproc_timer (gpointer data) if (s->running_preview_error_p) { clear_preview_window (s); - again_p = False; + again_p = FALSE; } } @@ -4146,7 +3619,7 @@ check_subproc_timer (gpointer data) might be satisfied. */ if (--s->subproc_check_countdown <= 0) - again_p = False; + again_p = FALSE; if (again_p) return TRUE; /* re-execute timer */ @@ -4164,7 +3637,7 @@ check_subproc_timer (gpointer data) check whether the program is still running. The assumption here is that if the process didn't stay up for more than a couple of seconds, then either the program doesn't exist, or it doesn't - take a -window-id argument. + take a --window-id argument. */ static void schedule_preview_check (state *s) @@ -4176,27 +3649,28 @@ schedule_preview_check (state *s) fprintf (stderr, "%s: scheduling check\n", blurb()); if (s->subproc_check_timer_id) - gtk_timeout_remove (s->subproc_check_timer_id); + g_source_remove (s->subproc_check_timer_id); s->subproc_check_timer_id = - gtk_timeout_add (1000 / ticks, - check_subproc_timer, (gpointer) s); + g_timeout_add (1000 / ticks, + check_subproc_timer, (gpointer) s); s->subproc_check_countdown = ticks * seconds; } static Bool -screen_blanked_p (void) +screen_blanked_p (state *s) { Atom type; int format; unsigned long nitems, bytesafter; unsigned char *dataP = 0; - Display *dpy = GDK_DISPLAY(); - Bool blanked_p = False; + Display *dpy = s->dpy; + Bool blanked_p = FALSE; + if (!s->dpy) return FALSE; if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */ XA_SCREENSAVER_STATUS, - 0, 3, False, XA_INTEGER, + 0, 3, FALSE, XA_INTEGER, &type, &format, &nitems, &bytesafter, &dataP) == Success @@ -4221,15 +3695,15 @@ static int check_blanked_timer (gpointer data) { state *s = (state *) data; - Bool blanked_p = screen_blanked_p (); + Bool blanked_p = screen_blanked_p (s); if (blanked_p && s->running_preview_pid) { if (s->debug_p) fprintf (stderr, "%s: screen is blanked: killing preview\n", blurb()); - kill_preview_subproc (s, True); + kill_preview_subproc (s, TRUE); } - return True; /* re-execute timer */ + return TRUE; /* re-execute timer */ } @@ -4237,35 +3711,17 @@ check_blanked_timer (gpointer data) static Bool multi_screen_p (Display *dpy) { - monitor **monitors = scan_monitors (dpy); + monitor **monitors = dpy ? scan_monitors (dpy) : NULL; Bool ret = monitors && monitors[0] && monitors[1]; if (monitors) free_monitors (monitors); return ret; } -/* Setting window manager icon - */ - -static void -init_icon (GdkWindow *window) -{ - GdkBitmap *mask = 0; - GdkPixmap *pixmap = - gdk_pixmap_create_from_xpm_d (window, &mask, 0, - (gchar **) logo_50_xpm); - if (pixmap) - gdk_window_set_icon (window, 0, pixmap, mask); -} - - -/* The main demo-mode command loop. - */ - #if 0 static Bool -mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, - XrmRepresentation *type, XrmValue *value, XPointer closure) +xrm_mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, + XrmRepresentation *type, XrmValue *value, XPointer closure) { int i; for (i = 0; quarks[i]; i++) @@ -4281,17 +3737,31 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, fprintf (stderr, ": %s\n", (char *) value->addr); - return False; + return FALSE; +} +#endif /* 0 */ + + +static int +ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) +{ + return 0; } -#endif static Window gnome_screensaver_window (Display *dpy, char **name_ret) { - int nscreens = ScreenCount (dpy); + int nscreens; int i, screen; Window gnome_window = 0; + XErrorHandler old_handler; + + if (!dpy) return 0; + XSync (dpy, FALSE); + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + + nscreens = ScreenCount (dpy); for (screen = 0; screen < nscreens; screen++) { Window root = RootWindow (dpy, screen); @@ -4309,7 +3779,7 @@ gnome_screensaver_window (Display *dpy, char **name_ret) unsigned long nitems, bytesafter; unsigned char *name; if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128, - False, XA_STRING, &type, &format, &nitems, + FALSE, XA_STRING, &type, &format, &nitems, &bytesafter, &name) == Success && type != None @@ -4329,25 +3799,29 @@ gnome_screensaver_window (Display *dpy, char **name_ret) if (gnome_window) break; } + + XSync (dpy, FALSE); + XSetErrorHandler (old_handler); return gnome_window; } + static Bool -gnome_screensaver_active_p (char **name_ret) +gnome_screensaver_active_p (state *s, char **name_ret) { - Display *dpy = GDK_DISPLAY(); - Window w = gnome_screensaver_window (dpy, name_ret); - return (w ? True : False); + Window w = gnome_screensaver_window (s->dpy, name_ret); + return (w ? TRUE : FALSE); } + static void -kill_gnome_screensaver (void) +kill_gnome_screensaver (state *s) { - Display *dpy = GDK_DISPLAY(); - Window w = gnome_screensaver_window (dpy, NULL); - if (w) XKillClient (dpy, (XID) w); + Window w = gnome_screensaver_window (s->dpy, NULL); + if (w) XKillClient (s->dpy, (XID) w); } + static Bool kde_screensaver_active_p (void) { @@ -4359,17 +3833,17 @@ kde_screensaver_active_p (void) FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null", "r"); char buf[255]; - if (!p) return False; - if (!fgets (buf, sizeof(buf)-1, p)) return False; + if (!p) return FALSE; + if (!fgets (buf, sizeof(buf)-1, p)) return FALSE; pclose (p); if (!strcmp (buf, "true\n")) - return True; + return TRUE; else - return False; + return FALSE; } static void -kill_kde_screensaver (void) +kill_kde_screensaver (state *s) { /* Use empty body to kill warning from gcc -Wall with "warning: ignoring return value of 'system', @@ -4383,13 +3857,13 @@ static int the_network_is_not_the_computer (gpointer data) { state *s = (state *) data; - Display *dpy = GDK_DISPLAY(); + Display *dpy = s->dpy; char *rversion = 0, *ruser = 0, *rhost = 0; char *luser, *lhost; char *msg = 0; char *oname = 0; struct passwd *p = getpwuid (getuid ()); - const char *d = DisplayString (dpy); + const char *d = dpy ? DisplayString (dpy) : ":0.0"; # if defined(HAVE_UNAME) struct utsname uts; @@ -4406,7 +3880,8 @@ the_network_is_not_the_computer (gpointer data) else luser = "???"; - server_xscreensaver_version (dpy, &rversion, &ruser, &rhost); + if (dpy) + server_xscreensaver_version (dpy, &rversion, &ruser, &rhost); /* Make a buffer that's big enough for a number of copies of all the strings, plus some. */ @@ -4419,11 +3894,10 @@ the_network_is_not_the_computer (gpointer data) 1024)); *msg = 0; - if (!rversion || !*rversion) + if ((!rversion || !*rversion) && !s->debug_p) { sprintf (msg, - _("Warning:\n\n" - "The XScreenSaver daemon doesn't seem to be running\n" + _("The XScreenSaver daemon doesn't seem to be running\n" "on display \"%.25s\". Launch it now?"), d); } @@ -4432,9 +3906,8 @@ the_network_is_not_the_computer (gpointer data) /* Warn that the two processes are running as different users. */ sprintf(msg, - _("Warning:\n\n" - "%s is running as user \"%s\" on host \"%s\".\n" - "But the xscreensaver managing display \"%s\"\n" + _("%s is running as user \"%s\" on host \"%s\".\n" + "But the xscreensaver managing display \"%.25s\"\n" "is running as user \"%s\" on host \"%s\".\n" "\n" "Since they are different users, they won't be reading/writing\n" @@ -4457,8 +3930,7 @@ the_network_is_not_the_computer (gpointer data) /* Warn that the two processes are running on different hosts. */ sprintf (msg, - _("Warning:\n\n" - "%s is running as user \"%s\" on host \"%s\".\n" + _("%s is running as user \"%s\" on host \"%s\".\n" "But the xscreensaver managing display \"%s\"\n" "is running as user \"%s\" on host \"%s\".\n" "\n" @@ -4474,13 +3946,12 @@ the_network_is_not_the_computer (gpointer data) progname, lhost, luser); } - else if (!!strcmp (rversion, s->short_version)) + else if (rversion && *rversion && !!strcmp (rversion, s->short_version)) { /* Warn that the version numbers don't match. */ sprintf (msg, - _("Warning:\n\n" - "This is %s version %s.\n" + _("This is %s version %s.\n" "But the xscreensaver managing display \"%s\"\n" "is version %s. This could cause problems.\n" "\n" @@ -4493,7 +3964,7 @@ the_network_is_not_the_computer (gpointer data) validate_image_directory_quick (s); if (*msg) - warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1); + warning_dialog_1 (s->window, _("Warning"), msg, D_LAUNCH); if (rversion) free (rversion); if (ruser) free (ruser); @@ -4506,42 +3977,38 @@ the_network_is_not_the_computer (gpointer data) running" dialog so that these are on top. Good enough. */ - if (gnome_screensaver_active_p (&oname)) + if (gnome_screensaver_active_p (s, &oname)) { char msg [1024]; sprintf (msg, - _("Warning:\n\n" - "The GNOME screen saver daemon (%s) appears to be running.\n" + _("The GNOME screen saver daemon (%s) appears to be running.\n" "It must be stopped for XScreenSaver to work properly.\n" "\n" "Stop the \"%s\" daemon now?\n"), oname, oname); - warning_dialog (s->toplevel_widget, msg, D_GNOME, 1); + warning_dialog_1 (s->window, _("Warning"), msg, D_GNOME); } - if (kde_screensaver_active_p ()) - warning_dialog (s->toplevel_widget, - _("Warning:\n\n" - "The KDE screen saver daemon appears to be running.\n" + if (kde_screensaver_active_p()) + warning_dialog_1 (s->window, _("Warning"), + _("The KDE screen saver daemon appears to be running.\n" "It must be stopped for XScreenSaver to work properly.\n" "\n" "Stop the KDE screen saver daemon now?\n"), - D_KDE, 1); + D_KDE); + + if (s->wayland_p) + warning_dialog (s->window, _("Warning"), + _("You are running Wayland rather than the X Window System.\n" + "\n" + "Under Wayland, idle-detection fails when non-X11 programs\n" + "are selected, meaning the screen may blank prematurely.\n" + "Also, locking is impossible.\n" + "\n" + "See the XScreenSaver manual for instructions on\n" + "configuring your system to use X11 instead of Wayland.\n")); - if (getenv ("WAYLAND_DISPLAY") || getenv ("WAYLAND_SOCKET")) - warning_dialog (s->toplevel_widget, - _("Warning:\n\n" - "You are running Wayland rather than the X Window System.\n" - "\n" - "Under Wayland, idle-detection fails when non-X11 programs\n" - "are selected, meaning the screen may blank prematurely.\n" - "Also, locking is impossible.\n" - "\n" - "See the XScreenSaver manual for instructions on\n" - "configuring your system to use X11 instead of Wayland.\n"), - D_NONE, 1); - - return False; /* Only run timer once */ + return FALSE; /* Only run timer once */ } @@ -4549,498 +4016,848 @@ the_network_is_not_the_computer (gpointer data) of the program that generated them. */ static int -demo_ehandler (Display *dpy, XErrorEvent *error) +x_error (Display *dpy, XErrorEvent *error) { - state *s = global_state_kludge; /* I hate C so much... */ - fprintf (stderr, "\nX error in %s:\n", blurb()); + fprintf (stderr, "\n%s: X error:\n", blurb()); XmuPrintDefaultErrorMessage (dpy, error, stderr); - kill_preview_subproc (s, False); - exit (-1); + /* No way to get 'state' in here... */ + /* kill_preview_subproc (s, FALSE); */ + exit (-1); /* Likewise, no way to call g_application_quit(). */ return 0; } -/* We use this error handler so that Gtk/Gdk errors are preceeded by the name - of the program that generated them; and also that we can ignore one - particular bogus error message that Gdk madly spews. - */ static void -g_log_handler (const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) -{ - /* Ignore the message "Got event for unknown window: 0x...". - Apparently some events are coming in for the xscreensaver window - (presumably reply events related to the ClientMessage) and Gdk - feels the need to complain about them. So, just suppress any - messages that look like that one. - */ - if (strstr (message, "unknown window")) - return; - - fprintf (stderr, "%s: %s-%s: %s%s", blurb(), - (log_domain ? log_domain : progclass), - (log_level == G_LOG_LEVEL_ERROR ? "error" : - log_level == G_LOG_LEVEL_CRITICAL ? "critical" : - log_level == G_LOG_LEVEL_WARNING ? "warning" : - log_level == G_LOG_LEVEL_MESSAGE ? "message" : - log_level == G_LOG_LEVEL_INFO ? "info" : - log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"), - message, - ((!*message || message[strlen(message)-1] != '\n') - ? "\n" : "")); +g_logger (const gchar *domain, GLogLevelFlags log_level, + const gchar *message, gpointer data) +{ + if (log_level & G_LOG_LEVEL_DEBUG) return; + if (log_level & G_LOG_LEVEL_INFO) return; + fprintf (stderr, "%s: %s: %s\n", blurb(), domain, message); + if (log_level & G_LOG_LEVEL_CRITICAL) exit (-1); } +/* Why are there two of these hooks and why does this one suck so hard?? */ +static GLogWriterOutput +g_other_logger (GLogLevelFlags log_level, const GLogField *fields, + gsize n_fields, gpointer data) +{ + int i; + GLogWriterOutput ret = G_LOG_WRITER_UNHANDLED; + if (log_level & G_LOG_LEVEL_DEBUG) return ret; + if (log_level & G_LOG_LEVEL_INFO) return ret; + for (i = 0; i < n_fields; i++) + { + const GLogField *field = &fields[i]; + if (strcmp (field->key, "MESSAGE")) continue; + fprintf (stderr, "%s: %s\n", blurb(), (char *) field->value); + ret = G_LOG_WRITER_HANDLED; + } + if (log_level & G_LOG_LEVEL_CRITICAL) exit (-1); + return ret; +} -STFU -static char *defaults[] = { -#include "XScreenSaver_ad.h" - 0 -}; -const char *usage = "[--display dpy] [--prefs | --settings]" - "\n\t\t [--debug] [--sync] [--no-xshm] [--configdir dir]"; +/**************************************************************************** + XScreenSaverDialog callbacks, referenced by prefs.ui. + ****************************************************************************/ -#if 0 -static void -print_widget_tree (GtkWidget *w, int depth) +/* The "Documentation" button on the Settings dialog */ +G_MODULE_EXPORT void +manual_cb (GtkButton *button, gpointer user_data) { - int i; - for (i = 0; i < depth; i++) - fprintf (stderr, " "); - fprintf (stderr, "%s\n", gtk_widget_get_name (w)); + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + Display *dpy = s->dpy; + saver_preferences *p = &s->prefs; + GtkWidget *list_widget = win->list; + int list_elt = selected_list_element (s); + int hack_number; + char *name, *name2, *cmd, *str; + char *oname = 0; + if (s->debug_p) fprintf (stderr, "%s: documentation button\n", blurb()); + if (list_elt < 0) return; + hack_number = s->list_elt_to_hack_number[list_elt]; + + flush_dialog_changes_and_save (s); + ensure_selected_item_visible (list_widget); + + name = strdup (p->screenhacks[hack_number]->command); + name2 = name; + oname = name; + while (isspace (*name2)) name2++; + str = name2; + while (*str && !isspace (*str)) str++; + *str = 0; + str = strrchr (name2, '/'); + if (str) name2 = str+1; - if (GTK_IS_LIST (w)) + cmd = get_string_resource (dpy, "manualCommand", "ManualCommand"); + if (cmd) { - for (i = 0; i < depth+1; i++) - fprintf (stderr, " "); - fprintf (stderr, "...list kids...\n"); + char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100); + strcpy (cmd2, "( "); + sprintf (cmd2 + strlen (cmd2), + cmd, + name2, name2, name2, name2); + strcat (cmd2, " ) &"); + if (system (cmd2) < 0) + fprintf (stderr, "%s: fork error\n", blurb()); + free (cmd2); } - else if (GTK_IS_CONTAINER (w)) + else { - GList *kids = gtk_container_children (GTK_CONTAINER (w)); - while (kids) - { - print_widget_tree (GTK_WIDGET (kids->data), depth+1); - kids = kids->next; - } + warning_dialog (s->window, _("Error"), + _("no `manualCommand' resource set.")); } -} -#endif /* 0 */ -static int -delayed_scroll_kludge (gpointer data) -{ - state *s = (state *) data; - GtkWidget *w = GTK_WIDGET (name_to_widget (s, "list")); - ensure_selected_item_visible (w); + free (oname); +} - /* Oh, this is just fucking lovely, too. */ - w = GTK_WIDGET (name_to_widget (s, "preview")); - gtk_widget_hide (w); - gtk_widget_show (w); - return FALSE; /* do not re-execute timer */ +static void +settings_sync_cmd_text (state *s) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); + GtkWidget *cmd = GTK_WIDGET (dialog->cmd_text); + char *cmd_line; + if (! s->cdata) return; + cmd_line = get_configurator_command_line (s->cdata, FALSE); + gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); + free (cmd_line); } -static GtkWidget * -create_xscreensaver_demo (void) +/* The "Advanced" button on the settings dialog. */ +G_MODULE_EXPORT void +settings_adv_cb (GtkButton *button, gpointer user_data) { - GtkWidget *nb; + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + GtkNotebook *notebook = GTK_NOTEBOOK (dialog->opt_notebook); + if (s->debug_p) fprintf (stderr, "%s: settings advanced button\n", blurb()); + settings_sync_cmd_text (s); + gtk_notebook_set_current_page (notebook, 1); +} - nb = name_to_widget (global_state_kludge, "preview_notebook"); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nb), FALSE); - return name_to_widget (global_state_kludge, "xscreensaver_demo"); +/* The "Standard" button on the settings dialog. */ +G_MODULE_EXPORT void +settings_std_cb (GtkButton *button, gpointer user_data) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + GtkNotebook *notebook = GTK_NOTEBOOK (dialog->opt_notebook); + if (s->debug_p) fprintf (stderr, "%s: settings standard button\n", blurb()); + settings_sync_cmd_text (s); + gtk_notebook_set_current_page (notebook, 0); } -static GtkWidget * -create_xscreensaver_settings_dialog (void) + +/* The "Reset to Defaults" button on the settings dialog. */ +G_MODULE_EXPORT void +settings_reset_cb (GtkButton *button, gpointer user_data) { - GtkWidget *w, *box; + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + GtkWidget *cmd = GTK_WIDGET (dialog->cmd_text); + state *s = &win->state; + char *cmd_line; + if (s->debug_p) fprintf (stderr, "%s: settings reset button\n", blurb()); + if (! s->cdata) return; + cmd_line = get_configurator_command_line (s->cdata, TRUE); + gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line); + free (cmd_line); + populate_popup_window (s); +} - box = name_to_widget (global_state_kludge, "dialog_action_area"); - w = name_to_widget (global_state_kludge, "adv_button"); - gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (box), w, TRUE); +/* Called when "Advanced/Standard" buttons change the displayed page. */ +G_MODULE_EXPORT void +settings_switch_page_cb (GtkNotebook *notebook, GtkWidget *page, + gint page_num, gpointer user_data) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + GtkWidget *adv = dialog->adv_button; + GtkWidget *std = dialog->std_button; + if (s->debug_p) fprintf (stderr, "%s: settings page changed\n", blurb()); - w = name_to_widget (global_state_kludge, "std_button"); - gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (box), w, TRUE); + if (page_num == 0) + { + gtk_widget_show (adv); + gtk_widget_hide (std); + } + else if (page_num == 1) + { + gtk_widget_hide (adv); + gtk_widget_show (std); + } + else + abort(); - return name_to_widget (global_state_kludge, "xscreensaver_settings_dialog"); + /* Nobody uses the "Advanced" tab. Let's just hide it. + (The tab still needs to be there, since the 'cmd_text' widget is + what gets stored into the .xscreensaver file.) */ + gtk_widget_hide (adv); + gtk_widget_hide (std); } -int -main (int argc, char **argv) +/* The "Cancel" button on the Settings dialog. */ +G_MODULE_EXPORT void +settings_cancel_cb (GtkWidget *button, gpointer user_data) { - XtAppContext app; - state S, *s; - saver_preferences *p; - Bool prefs_p = False; - Bool settings_p = False; - int i; - Display *dpy; - Widget toplevel_shell; - char *real_progname = argv[0]; - char *window_title; - char *geom = 0; - char *str; + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + if (s->debug_p) fprintf (stderr, "%s: settings cancel button\n", blurb()); + gtk_widget_hide (GTK_WIDGET (dialog)); + gtk_widget_unrealize (GTK_WIDGET (dialog)); + + /* Restart the hack running in the Preview window with the reset options. */ + schedule_preview (s, dialog->unedited_cmdline); +} -# ifdef ENABLE_NLS - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - textdomain (GETTEXT_PACKAGE); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -# endif /* ENABLE_NLS */ - str = strrchr (real_progname, '/'); - if (str) real_progname = str+1; +/* The "Ok" button on the Settings dialog. */ +G_MODULE_EXPORT void +settings_ok_cb (GtkWidget *button, gpointer user_data) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (user_data); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + GtkNotebook *notebook = GTK_NOTEBOOK (dialog->opt_notebook); + int page = gtk_notebook_get_current_page (notebook); + if (s->debug_p) fprintf (stderr, "%s: settings ok button\n", blurb()); - s = &S; - memset (s, 0, sizeof(*s)); - s->initializing_p = True; - p = &s->prefs; + if (page == 0) + /* Regenerate the command-line from the widget contents before saving. + But don't do this if we're looking at the command-line page already, + or we will blow away what they typed... */ + settings_sync_cmd_text (s); - global_state_kludge = s; /* I hate C so much... */ + flush_popup_changes_and_save (s); + gtk_widget_hide (GTK_WIDGET (dialog)); + gtk_widget_unrealize (GTK_WIDGET (dialog)); +} - progname = real_progname; - s->short_version = XSCREENSAVER_VERSION; +/* Called when any widget value is changed in the Settings dialog. */ +static void +dialog_change_cb (GtkWidget *widget, gpointer user_data) +{ + state *s = (state *) user_data; + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); + char *cur_cmd, *def_cmd; + const char *prev_cmd; + if (!dialog || !s->cdata) return; + settings_sync_cmd_text (s); + cur_cmd = get_configurator_command_line (s->cdata, FALSE); + def_cmd = get_configurator_command_line (s->cdata, TRUE); + prev_cmd = dialog->unedited_cmdline; - /* Register our error message logger for every ``log domain'' known. - There's no way to do this globally, so I grepped the Gtk/Gdk sources - for all of the domains that seem to be in use. - */ - { - const char * const domains[] = { 0, - "Gtk", "Gdk", "GLib", "GModule", - "GThread", "Gnome", "GnomeUI" }; - for (i = 0; i < countof(domains); i++) - g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0); - } + /* "Reset to Defaults" button enabled only if current cmd is not default. */ + gtk_widget_set_sensitive (dialog->reset_button, + !!strcmp (cur_cmd, def_cmd)); - /* This is gross, but Gtk understands --display and not -display... - */ - for (i = 1; i < argc; i++) - if (argv[i][0] && argv[i][1] && - !strncmp(argv[i], "-display", strlen(argv[i]))) - argv[i] = "--display"; + /* "Save" button enabled only if current cmd is edited. */ + gtk_widget_set_sensitive (dialog->ok_button, + !!strcmp (cur_cmd, prev_cmd)); + /* Restart the hack running in the Preview window with the prevailing, + un-saved set of options, for a realtime preview of what they do. */ + schedule_preview (s, cur_cmd); - /* We need to parse this arg really early... Sigh. */ - for (i = 1; i < argc; i++) - { - if (argv[i] && - (!strcmp(argv[i], "--debug") || - !strcmp(argv[i], "-debug") || - !strcmp(argv[i], "-d"))) - { - int j; - s->debug_p = True; - for (j = i; j < argc; j++) /* remove it from the list */ - argv[j] = argv[j+1]; - argc--; - i--; - } - else if (argv[i] && - argc > i+1 && - *argv[i+1] && - (!strcmp(argv[i], "-geometry") || - !strcmp(argv[i], "-geom") || - !strcmp(argv[i], "-geo") || - !strcmp(argv[i], "-g"))) - { - int j; - geom = argv[i+1]; - for (j = i; j < argc; j++) /* remove them from the list */ - argv[j] = argv[j+2]; - argc -= 2; - i -= 2; - } - else if (argv[i] && - argc > i+1 && - *argv[i+1] && - (!strcmp(argv[i], "--configdir"))) - { - int j; - struct stat st; - hack_configuration_path = argv[i+1]; - for (j = i; j < argc; j++) /* remove them from the list */ - argv[j] = argv[j+2]; - argc -= 2; - i -= 2; - - if (0 != stat (hack_configuration_path, &st)) - { - char buf[255]; - sprintf (buf, "%s: %.200s", blurb(), hack_configuration_path); - perror (buf); - exit (1); - } - else if (!S_ISDIR (st.st_mode)) - { - fprintf (stderr, "%s: not a directory: %s\n", - blurb(), hack_configuration_path); - exit (1); - } - } - } + free (cur_cmd); + free (def_cmd); +} - if (s->debug_p) - fprintf (stderr, "%s: using config directory \"%s\"\n", - progname, hack_configuration_path); +/* Fill in the contents of the "Settings" dialog for the current hack. + It may or may not currently be visible. + */ +static void +populate_popup_window (state *s) +{ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); + GtkLabel *doc = dialog ? GTK_LABEL (dialog->doc) : 0; + char *doc_string = 0; - /* Let Gtk open the X connection, then initialize Xt to use that - same connection. Doctor Frankenstein would be proud. - */ - gtk_init (&argc, &argv); + if (s->cdata) + { + free_conf_data (s->cdata); + s->cdata = 0; + } + { + saver_preferences *p = &s->prefs; + int list_elt = selected_list_element (s); + int hack_number = (list_elt >= 0 && list_elt < s->list_count + ? s->list_elt_to_hack_number[list_elt] + : -1); + screenhack *hack = (hack_number >= 0 ? p->screenhacks[hack_number] : 0); + if (hack && dialog) + { + GtkWidget *parent = dialog->settings_vbox; + GtkWidget *cmd = GTK_WIDGET (dialog->cmd_text); + const char *cmd_line = gtk_entry_get_text (GTK_ENTRY (cmd)); + if (!cmd_line) abort(); + s->cdata = load_configurator (cmd_line, dialog_change_cb, s, + s->debug_p); + dialog_change_cb (NULL, s); + if (s->cdata && s->cdata->widget) + gtk_box_pack_start (GTK_BOX (parent), s->cdata->widget, + TRUE, TRUE, 0); - /* We must read exactly the same resources as xscreensaver. - That means we must have both the same progclass *and* progname, - at least as far as the resource database is concerned. So, - put "xscreensaver" in argv[0] while initializing Xt. - */ - argv[0] = "xscreensaver"; - progname = argv[0]; + /* Make the pretty name on the tab boxes include the year and be bold. + */ + if (s->cdata && s->cdata->year) + { + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + Display *dpy = s->dpy; + GtkFrame *frame1 = GTK_FRAME (win->preview_frame); + GtkFrame *frame2 = GTK_FRAME (dialog->opt_frame); + char *pretty_name = (hack->name + ? strdup (hack->name) + : make_hack_name (dpy, hack->command)); + char *s2 = (char *) malloc (strlen (pretty_name) + 20); + sprintf (s2, "%s (%d)", pretty_name, s->cdata->year); + free (pretty_name); + pretty_name = s2; + gtk_frame_set_label (frame1, _(pretty_name)); + gtk_frame_set_label (frame2, _(pretty_name)); + gtk_label_set_use_markup ( /* Must be after set_label */ + GTK_LABEL (gtk_frame_get_label_widget (frame1)), TRUE); + gtk_label_set_use_markup ( + GTK_LABEL (gtk_frame_get_label_widget (frame2)), TRUE); + free (pretty_name); + } + } + } - /* Teach Xt to use the Display that Gtk/Gdk have already opened. - */ - XtToolkitInitialize (); - app = XtCreateApplicationContext (); - dpy = GDK_DISPLAY(); - XtAppSetFallbackResources (app, defaults); - XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv); - toplevel_shell = XtAppCreateShell (progname, progclass, - applicationShellWidgetClass, - dpy, 0, 0); - - dpy = XtDisplay (toplevel_shell); - db = XtDatabase (dpy); - XtGetApplicationNameAndClass (dpy, (char **) &progname, &progclass); - XSetErrorHandler (demo_ehandler); - - /* Let's just ignore these. They seem to confuse Irix Gtk... */ - signal (SIGPIPE, SIG_IGN); - - /* After doing Xt-style command-line processing, complain about any - unrecognized command-line arguments. - */ - for (i = 1; i < argc; i++) + doc_string = (s->cdata && s->cdata->description && *s->cdata->description + ? _(s->cdata->description) + : 0); + doc_string = hreffify (doc_string); + if (doc) { - char *str = argv[i]; - if (str[0] == '-' && str[1] == '-') - str++; - if (!strcmp (str, "-prefs")) - prefs_p = True; - else if (!strcmp (str, "-settings")) - settings_p = True; - else - { - fprintf (stderr, _("%s: unknown option: %s\n"), real_progname, - argv[i]); - fprintf (stderr, "%s: %s\n", real_progname, usage); - exit (1); - } + GtkWidget *w = dialog->dialog_vbox; + gtk_label_set_text (doc, (doc_string + ? doc_string + : _("No description available."))); + gtk_label_set_use_markup (doc, TRUE); + + /* Shrink the dialog to the minimum viable size. */ + gtk_window_resize (GTK_WINDOW (dialog), 1, 1); + + gtk_widget_hide (w); + gtk_widget_unrealize (w); + gtk_widget_realize (w); + gtk_widget_show (w); } - /* Load the init file, which may end up consulting the X resource database - and the site-wide app-defaults file. Note that at this point, it's - important that `progname' be "xscreensaver", rather than whatever - was in argv[0]. - */ - p->db = db; - s->multi_screen_p = multi_screen_p (dpy); - - init_xscreensaver_atoms (dpy); - hack_environment (s); /* must be before initialize_sort_map() */ - - load_init_file (dpy, p); - initialize_sort_map (s); - - /* Now that Xt has been initialized, and the resources have been read, - we can set our `progname' variable to something more in line with - reality. - */ - progname = real_progname; + /* Also set the documentation on the main window, below the preview. */ + { + GtkLabel *doc2 = GTK_LABEL (win->short_preview_label); + GtkLabel *doc3 = GTK_LABEL (win->preview_author_label); + char *s2 = 0; + char *s3 = 0; + if (doc_string) + { + /* Keep only the first paragraph, and the last line. + Omit everything in between. */ + const char *second_para = strstr (doc_string, "\n\n"); + const char *last_line = strrchr (doc_string, '\n'); + s2 = strdup (doc_string); + if (second_para) + s2[second_para - doc_string] = 0; + if (last_line) + s3 = strdup (last_line + 1); + } -#if 0 - /* Print out all the resources we read. */ - { - XrmName name = { 0 }; - XrmClass class = { 0 }; - int count = 0; - XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper, - (POINTER) &count); + gtk_label_set_text (doc2, (s2 + ? _(s2) + : _("No description available."))); + gtk_label_set_text (doc3, (s3 ? _(s3) : "")); + if (s2) free (s2); + if (s3) free (s3); } -#endif - init_xscreensaver_atoms (dpy); + if (doc_string) + free (doc_string); +} - /* Create the window and all its widgets. - */ - s->base_widget = create_xscreensaver_demo (); - s->popup_widget = create_xscreensaver_settings_dialog (); - s->toplevel_widget = s->base_widget; +static void +sensitize_demo_widgets (state *s, Bool sensitive_p) +{ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); + gtk_widget_set_sensitive (win->demo, sensitive_p); + gtk_widget_set_sensitive (win->settings, sensitive_p); + if (dialog) + { + gtk_widget_set_sensitive (dialog->cmd_label, sensitive_p); + gtk_widget_set_sensitive (dialog->cmd_text, sensitive_p); + gtk_widget_set_sensitive (dialog->manual, sensitive_p); + gtk_widget_set_sensitive (dialog->visual, sensitive_p); + gtk_widget_set_sensitive (dialog->visual_combo, sensitive_p); + } +} - /* Set the main window's title. */ - { - char *base_title = _("Screensaver Preferences"); - char *v = (char *) strdup(strchr(screensaver_id, ' ')); - char *s1, *s2, *s3, *s4; - s1 = (char *) strchr(v, ' '); s1++; - s2 = (char *) strchr(s1, ' '); - s3 = (char *) strchr(v, '('); s3++; - s4 = (char *) strchr(s3, ')'); - *s2 = 0; - *s4 = 0; - - window_title = (char *) malloc (strlen (base_title) + - strlen (progclass) + - strlen (s1) + strlen (s3) + - 100); - sprintf (window_title, "%s (%s %s, %s)", base_title, progclass, s1, s3); - gtk_window_set_title (GTK_WINDOW (s->toplevel_widget), window_title); - gtk_window_set_title (GTK_WINDOW (s->popup_widget), window_title); - free (v); - } - /* Adjust the (invisible) notebooks on the popup dialog... */ - { - GtkNotebook *notebook = - GTK_NOTEBOOK (name_to_widget (s, "opt_notebook")); - GtkWidget *std = GTK_WIDGET (name_to_widget (s, "std_button")); - int page = 0; +/* Flush out any changes made in the popup dialog box (where changes + take place only when the OK button is clicked.) + */ +static Bool +flush_popup_changes_and_save (state *s) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (s->dialog); - gtk_widget_hide (std); + Bool changed = FALSE; + saver_preferences *p = &s->prefs; + int list_elt = selected_list_element (s); - gtk_notebook_set_page (notebook, page); - gtk_notebook_set_show_tabs (notebook, False); - } + GtkEntry *cmd = GTK_ENTRY (dialog->cmd_text); + GtkWidget *vis = GTK_WIDGET (dialog->visual_combo); + GtkEntry *visent = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (vis))); + + const char *visual = gtk_entry_get_text (visent); + const char *command = gtk_entry_get_text (cmd); + + char c; + unsigned long id; + + if (s->saving_p) return FALSE; + s->saving_p = TRUE; + + if (list_elt < 0) + goto DONE; + + if (maybe_reload_init_file (s) != 0) + { + changed = TRUE; + goto DONE; + } - /* Various other widget initializations... + /* Sanity-check and canonicalize whatever the user typed into the combo box. */ - gtk_signal_connect (GTK_OBJECT (s->toplevel_widget), "delete_event", - GTK_SIGNAL_FUNC (wm_toplevel_close_cb), - (gpointer) s); - gtk_signal_connect (GTK_OBJECT (s->popup_widget), "delete_event", - GTK_SIGNAL_FUNC (wm_popup_close_cb), - (gpointer) s); + if (!strcasecmp (visual, "")) visual = ""; + else if (!strcasecmp (visual, "any")) visual = ""; + else if (!strcasecmp (visual, "default")) visual = "Default"; + else if (!strcasecmp (visual, "default-n")) visual = "Default-N"; + else if (!strcasecmp (visual, "default-i")) visual = "Default-I"; + else if (!strcasecmp (visual, "best")) visual = "Best"; + else if (!strcasecmp (visual, "mono")) visual = "Mono"; + else if (!strcasecmp (visual, "monochrome")) visual = "Mono"; + else if (!strcasecmp (visual, "gray")) visual = "Gray"; + else if (!strcasecmp (visual, "grey")) visual = "Gray"; + else if (!strcasecmp (visual, "color")) visual = "Color"; + else if (!strcasecmp (visual, "gl")) visual = "GL"; + else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray"; + else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor"; + else if (!strcasecmp (visual, "truecolor")) visual = "TRUEColor"; + else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale"; + else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale"; + else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor"; + else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor"; + else if (1 == sscanf (visual, " %lu %c", &id, &c)) ; + else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ; + else visual = ""; - populate_hack_list (s); - populate_prefs_page (s); - sensitize_demo_widgets (s, False); - scroll_to_current_hack (s); + changed = flush_changes (s, list_elt, -1, command, visual); + if (changed) + { + demo_write_init_file (s, p); - /* Hook up callbacks to the items on the mode menu. */ - gtk_signal_connect (GTK_OBJECT (name_to_widget (s, "mode_menu")), - "changed", GTK_SIGNAL_FUNC (mode_menu_item_cb), - (gpointer) s); - if (! s->multi_screen_p) + /* Do this to re-launch the hack if (and only if) the command line + has changed. */ + populate_demo_window (s, selected_list_element (s)); + } + + DONE: + s->saving_p = FALSE; + return changed; +} + + +/**************************************************************************** + + XScreenSaverWindow + + ****************************************************************************/ + + +static void +xscreensaver_window_destroy (GObject *object) +{ + /* Called by WM close box, but not by File / Quit */ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (object); + quit_menu_cb (NULL, win); /* Shouldn't return? */ + G_OBJECT_CLASS (xscreensaver_window_parent_class)->dispose (object); +} + + +/* gtk_window_move() sets the origin of the window's WM decorations, but + GTK's "configure-event" returns the root-relative origin of the window + within the decorations, so the "configure-event" numbers are too large by + the size of the decorations (title bar and border). Without compensating + for this, the window would move down and slightly to the right every time + we saved and restored. GDK provides no way to find those numbers, so we + have to hack it out X11 style... + */ +static void +wm_decoration_origin (GtkWindow *gtkw, int *x, int *y) +{ + Display *dpy = gdk_x11_get_default_xdisplay(); + GdkWindow *gdkw = gtk_widget_get_window (GTK_WIDGET (gtkw)); + Window xw = gdk_x11_window_get_xid (gdkw); + + Window root, parent, *kids; + unsigned int nkids; + + Atom type = None; + int format; + unsigned long nitems, bytesafter; + unsigned char *data; + + static Atom swm_vroot = 0; + XWindowAttributes xgwa; + + if (!dpy || !xw) return; + if (! XQueryTree (dpy, xw, &root, &parent, &kids, &nkids)) + abort (); + + if (parent == root) /* No window above us at all */ + return; + + if (! swm_vroot) + swm_vroot = XInternAtom (dpy, "__SWM_VROOT", FALSE); + + /* If parent is a virtual root, there is no intervening WM decoration. */ + if (XGetWindowProperty (dpy, parent, swm_vroot, + 0, 0, FALSE, AnyPropertyType, + &type, &format, &nitems, &bytesafter, + (unsigned char **) &data) + == Success + && type != None) + return; + + /* If we have a parent, it is the WM decoration, so use its origin. */ + if (! XGetWindowAttributes (dpy, parent, &xgwa)) + abort(); + *x = xgwa.x; + *y = xgwa.y; +} + + +static void +save_window_position (state *s, GtkWindow *win, int x, int y, Bool dialog_p) +{ + saver_preferences *p = &s->prefs; + int win_x, win_y, dialog_x, dialog_y; + char dummy; + char *old = p->settings_geom; + char str[100]; + + if (!s->dpy || s->wayland_p) return; + wm_decoration_origin (win, &x, &y); + + if (!old || !*old || + 4 != sscanf (old, " %d , %d %d , %d %c", + &win_x, &win_y, &dialog_x, &dialog_y, &dummy)) + win_x = win_y = dialog_x = dialog_y = -1; + + if (dialog_p) + dialog_x = x, dialog_y = y; + else + win_x = x, win_y = y; + + sprintf (str, "%d,%d %d,%d", win_x, win_y, dialog_x, dialog_y); + + if (old && !strcmp (old, str)) return; /* unchanged */ + + p->settings_geom = strdup (str); + + if (s->debug_p) + fprintf (stderr, "%s: geom: %s => %s\n", blurb(), old, str); + + /* This writes the .xscreensaver file repeatedly as the window is dragged, + which is too much. We could defer it with a timer. But instead let's + just not save it upon resize, and only save the positions once the + file is written due to some other change. + */ + /* demo_write_init_file (s, p); */ + if (old) free (old); +} + + +static void +restore_window_position (state *s, GtkWindow *window, Bool dialog_p) +{ + saver_preferences *p = &s->prefs; + int win_x, win_y, dialog_x, dialog_y, x, y; + char dummy; + char *old = p->settings_geom; + + if (!old || !*old || + 4 != sscanf (old, " %d , %d %d , %d %c", + &win_x, &win_y, &dialog_x, &dialog_y, &dummy)) + win_x = win_y = dialog_x = dialog_y = -1; + + if (dialog_p) + x = dialog_x, y = dialog_y; + else + x = win_x, y = win_y; + + if (x <= 0 || y <= 0) return; + + if (s->debug_p) + fprintf (stderr, "%s: restore origin: %d,%d\n", blurb(), x, y); + gtk_window_move (window, x, y); +} + + +/* When the window is moved, save the new origin in .xscreensaver. */ +static gboolean +xscreensaver_window_resize_cb (GtkWindow *window, GdkEvent *event, + gpointer data) +{ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (window); + state *s = &win->state; + save_window_position (s, GTK_WINDOW (win), + event->configure.x, event->configure.y, FALSE); + return FALSE; +} + + +static int +delayed_scroll_kludge (gpointer data) +{ + state *s = (state *) data; + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (s->window); + GtkWidget *list_widget = win->list; + ensure_selected_item_visible (list_widget); + return FALSE; /* do not re-execute timer */ +} + + +static void +quit_action_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data) +{ + quit_menu_cb (NULL, user_data); +} + + +static GActionEntry app_entries[] = { + { "quit", quit_action_cb, NULL, NULL, NULL }, +/* + { "undo", undo_action_cb, NULL, NULL, NULL }, + { "redo", redo_action_cb, NULL, NULL, NULL }, + { "cut", cut_action_cb, NULL, NULL, NULL }, + { "copy", copy_action_cb, NULL, NULL, NULL }, + { "paste", paste_action_cb, NULL, NULL, NULL }, + { "delete", delete_action_cb, NULL, NULL, NULL }, +*/ +}; + +/* #### I don't know how to make the accelerators show up on the menu items, + and I don't understand the difference between "callbacks" and "actions". + I see examples in other .ui files that do things like: + + + + + + or + + + File +
+ + Activate + app.activate + + but when I put variants of that in demo.ui, nothing shows up. + + It would be nice to have an "Edit" menu with working text-editing commands + on it, for use with our various text fields. One would think that a GUI + toolkit would provide boilerplate for such things, but nooooo... + */ +const gchar *accels[][2] = { + { "app.quit", "Q" }, +/* + { "app.undo", "Z" }, + { "app.redo", "Y" }, + { "app.cut", "X" }, + { "app.copy", "C" }, + { "app.paste", "V" }, +*/ +}; + + +static void +xscreensaver_window_realize (GtkWidget *self, gpointer user_data) +{ + XScreenSaverWindow *win = XSCREENSAVER_WINDOW (self); + state *s = &win->state; + saver_preferences *p = &s->prefs; + + s->initializing_p = TRUE; + s->short_version = XSCREENSAVER_VERSION; + s->window = GTK_WINDOW (win); + + s->dpy = gdk_x11_get_default_xdisplay(); + + /* Debian 11.4, Gtk 3.24.24, 2022: under Wayland, get_default_xdisplay is + returning uninitialized data! However, gdk_x11_window_get_xid prints a + warning and returns NULL. So let's try that, and as a fallback, also try + and sanity check the contents of the Display structure... + */ + if (! gdk_x11_window_get_xid (gtk_widget_get_window (self))) { - GtkComboBox *opt = GTK_COMBO_BOX (name_to_widget (s, "mode_menu")); - GtkTreeModel *list = gtk_combo_box_get_model (opt); - unsigned int i; - for (i = 0; i < countof(mode_menu_order); i++) + s->dpy = NULL; + s->wayland_p = TRUE; + } + + if (s->dpy) + { + if (ProtocolVersion (s->dpy) != 11 || + ProtocolRevision (s->dpy) != 0) { - /* The "random-same" mode menu item does not appear unless - there are multiple screens. - */ - if (mode_menu_order[i] == RANDOM_HACKS_SAME) - { - GtkTreeIter iter; - gtk_tree_model_iter_nth_child (list, &iter, NULL, i); - gtk_list_store_remove (GTK_LIST_STORE (list), &iter); - break; - } + fprintf (stderr, "%s: uninitialized data in Display: " + "protocol version %d.%d!\n", blurb(), + ProtocolVersion(s->dpy), ProtocolRevision(s->dpy)); + s->dpy = NULL; + s->wayland_p = TRUE; } - - /* recompute option-menu size */ - gtk_widget_unrealize (GTK_WIDGET (opt)); - gtk_widget_realize (GTK_WIDGET (opt)); } + /* If we don't have a display connection, then we are surely under Wayland + even if the environment variable is not set. + */ + if (!s->dpy && + !getenv ("WAYLAND_DISPLAY") && + !getenv ("WAYLAND_SOCKET")) + putenv ("WAYLAND_DISPLAY=probably"); + + if (getenv ("WAYLAND_DISPLAY") || + getenv ("WAYLAND_SOCKET")) + s->wayland_p = TRUE; - /* Handle the -prefs command-line argument. */ - if (prefs_p) + /* If GTK is running directly under Wayland, try to open an X11 connection + to XWayland anyway, so that get_string_resource and load_init_file work. + */ + if (! s->dpy) { - GtkNotebook *notebook = - GTK_NOTEBOOK (name_to_widget (s, "notebook")); - gtk_notebook_set_page (notebook, 1); + s->dpy = XOpenDisplay (NULL); + if (s->debug_p) + { + if (s->dpy) + fprintf (stderr, "%s: opened secondary XWayland connection\n", + blurb()); + else + fprintf (stderr, "%s: failed to open XWayland connection\n", + blurb()); + } } - free (window_title); - window_title = 0; + /* Teach Xt to use the Display that Gtk/Gdk have already opened. + */ + if (s->dpy) + { + XtAppContext app; + int argc = 0; + char *argv[2]; + const char *oprogname = progname; - /* After picking the default size, allow -geometry to override it. */ - if (geom) - gtk_window_parse_geometry (GTK_WINDOW (s->toplevel_widget), geom); + progname = "xscreensaver"; /* For X resources */ + argv[argc++] = (char *) progname; + argv[argc] = 0; - gtk_widget_show (s->toplevel_widget); - init_icon (GET_WINDOW (GTK_WIDGET (s->toplevel_widget))); /* after `show' */ - fix_preview_visual (s); + XtToolkitInitialize (); + app = XtCreateApplicationContext (); + XtAppSetFallbackResources (app, defaults); + XtDisplayInitialize (app, s->dpy, progname, progclass, 0, 0, &argc, argv); + /* Result discarded and leaked */ + XtAppCreateShell (progname, progclass, applicationShellWidgetClass, + s->dpy, 0, 0); + p->db = XtDatabase (s->dpy); + XSetErrorHandler (x_error); - /* Realize page zero, so that we can diddle the scrollbar when the - user tabs back to it -- otherwise, the current hack isn't scrolled - to the first time they tab back there, when started with "-prefs". - (Though it is if they then tab away, and back again.) + signal (SIGPIPE, SIG_IGN); /* Is this necessary? */ - #### Bah! This doesn't work. Gtk eats my ass! Someone who - #### understands this crap, explain to me how to make this work. - */ - gtk_widget_realize (name_to_widget (s, "demos_table")); + progname = oprogname; +# if 0 + /* Print out all the Xrm resources we read. */ + { + XrmName name = { 0 }; + XrmClass class = { 0 }; + int count = 0; + XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, xrm_mapper, + (void *) &count); + } +# endif + } - gtk_timeout_add (60 * 1000, check_blanked_timer, s); + s->multi_screen_p = multi_screen_p (s->dpy); + if (s->dpy) + init_xscreensaver_atoms (s->dpy); - /* Handle the --settings command-line argument. */ - if (settings_p) - gtk_timeout_add (500, settings_timer, 0); + hack_environment (s); /* must be before initialize_sort_map() */ + load_init_file (s->dpy, p); + initialize_sort_map (s); + s->dialog = g_object_new (XSCREENSAVER_DIALOG_TYPE, NULL); + XSCREENSAVER_DIALOG (s->dialog)->main = win; - /* Issue any warnings about the running xscreensaver daemon. - Wait a few seconds, in case things are still starting up. */ - if (! s->debug_p) - gtk_timeout_add (5 * 1000, the_network_is_not_the_computer, s); - - - if (time ((time_t *) 0) - XSCREENSAVER_RELEASED > 60*60*24*30*17) - warning_dialog (s->toplevel_widget, - _("Warning:\n\n" - "This version of xscreensaver is VERY OLD!\n" - "Please upgrade!\n" - "\n" - "https://www.jwz.org/xscreensaver/\n" - "\n" - "(If this is the latest version that your distro ships, then\n" - "your distro is doing you a disservice. Build from source.)\n" - ), - D_NONE, 7); - - /* Run the Gtk event loop, and not the Xt event loop. This means that - if there were Xt timers or fds registered, they would never get serviced, - and if there were any Xt widgets, they would never have events delivered. - Fortunately, we're using Gtk for all of the UI, and only initialized - Xt so that we could process the command line and use the X resource - manager. - */ - s->initializing_p = False; + gtk_window_set_transient_for (GTK_WINDOW (s->dialog), GTK_WINDOW (win)); - /* This totally sucks -- set a timer that whacks the scrollbar 0.5 seconds - after we start up. Otherwise, it always appears scrolled to the top - when in crapplet-mode. */ - gtk_timeout_add (500, delayed_scroll_kludge, s); + sensitize_menu_items (s, TRUE); + populate_hack_list (s); + populate_prefs_page (s); + sensitize_demo_widgets (s, FALSE); + scroll_to_current_hack (s); + if (s->dpy && !s->wayland_p) + fix_preview_visual (s); + if (! s->multi_screen_p) + hide_mode_menu_random_same (s); + + restore_window_position (s, GTK_WINDOW (self), FALSE); + g_timeout_add (60 * 1000, check_blanked_timer, s); -#if 1 + /* Attach the actions and their keybindings. */ + { + int i; + GtkApplication *app = gtk_window_get_application (GTK_WINDOW (win)); + g_action_map_add_action_entries (G_ACTION_MAP (app), + app_entries, countof (app_entries), + win); + for (i = 0; i < countof (accels); i++) + { + const gchar *a[2]; + a[0] = accels[i][1]; + a[1] = 0; + gtk_application_set_accels_for_action (GTK_APPLICATION (app), + accels[i][0], a); + } + } + +# if 0 /* Load every configurator in turn, to scan them for errors all at once. */ if (s->debug_p) { @@ -5052,13 +4869,235 @@ main (int argc, char **argv) if (d) free_conf_data (d); } } -#endif +# endif + + + /* Issue any warnings about the running xscreensaver daemon. + Wait a few seconds, in case things are still starting up. */ + g_timeout_add (5 * 1000, the_network_is_not_the_computer, s); + + /* This totally sucks -- set a timer that whacks the scrollbar 0.5 seconds + after we start up. Otherwise, it always appears scrolled to the top. */ + g_timeout_add (500, delayed_scroll_kludge, s); + + s->initializing_p = FALSE; +} + + +static void +xscreensaver_window_init (XScreenSaverWindow *win) +{ + gtk_widget_init_template (GTK_WIDGET (win)); + g_signal_connect (win, "destroy", + G_CALLBACK (xscreensaver_window_destroy), win); + g_signal_connect (win, "realize", + G_CALLBACK (xscreensaver_window_realize), win); + g_signal_connect (win, "configure-event", + G_CALLBACK (xscreensaver_window_resize_cb),win); +} + + +static void +xscreensaver_window_class_init (XScreenSaverWindowClass *class) +{ + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), + "/org/jwz/xscreensaver/demo.ui"); + + /* Fill in the widget fields in XScreenSaverWindow with the corresponding + objects created from demo.ui. */ +# undef W +# define W(NAME) \ + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), \ + XScreenSaverWindow, NAME); + ALL_WINDOW_WIDGETS +# undef W +} + + +/**************************************************************************** + + XScreenSaverDialog + ****************************************************************************/ - gtk_main (); +static void +xscreensaver_dialog_destroy (GObject *object) +{ + /* Called by WM close box, but not by File / Quit */ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (object); + XScreenSaverWindow *win = dialog->main; + flush_dialog_changes_and_save (&win->state); + G_OBJECT_CLASS (xscreensaver_dialog_parent_class)->dispose (object); +} + + +static void +xscreensaver_dialog_realize (GtkWidget *self, gpointer user_data) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (self); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + restore_window_position (s, GTK_WINDOW (self), TRUE); +} + + +/* When the window is moved, save the new origin in .xscreensaver. */ +static gboolean +xscreensaver_dialog_resize_cb (GtkWindow *window, GdkEvent *event, + gpointer data) +{ + XScreenSaverDialog *dialog = XSCREENSAVER_DIALOG (window); + XScreenSaverWindow *win = dialog->main; + state *s = &win->state; + save_window_position (s, GTK_WINDOW (dialog), + event->configure.x, event->configure.y, TRUE); + return FALSE; +} + + +/* The WM close box. */ +static gboolean +xscreensaver_dialog_delete_cb (GtkWidget *self, GdkEvent *event, + gpointer user_data) +{ + settings_cancel_cb (GTK_WIDGET (self), user_data); + return TRUE; /* Do not run other handlers */ +} + + +static void +xscreensaver_dialog_init (XScreenSaverDialog *win) +{ + gtk_widget_init_template (GTK_WIDGET (win)); + g_signal_connect (win, "destroy", + G_CALLBACK (xscreensaver_dialog_destroy), win); + g_signal_connect (win, "realize", + G_CALLBACK (xscreensaver_dialog_realize), win); + g_signal_connect (win, "configure-event", + G_CALLBACK (xscreensaver_dialog_resize_cb), win); + g_signal_connect (win, "delete-event", + G_CALLBACK (xscreensaver_dialog_delete_cb), win); +} + + +static void +xscreensaver_dialog_class_init (XScreenSaverDialogClass *class) +{ + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), + "/org/jwz/xscreensaver/prefs.ui"); + + /* Fill in the widget fields in XScreenSaverDialog with the corresponding + objects created from prefs.ui. */ +# undef W +# define W(NAME) \ + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), \ + XScreenSaverDialog, NAME); + ALL_DIALOG_WIDGETS +# undef W +} + + +/**************************************************************************** + + XScreenSaverApp + + ****************************************************************************/ + + +static void +xscreensaver_app_init (XScreenSaverApp *app) +{ +} - kill_preview_subproc (s, False); - exit (0); + +static void +xscreensaver_app_startup (GApplication *app) +{ + G_APPLICATION_CLASS (xscreensaver_app_parent_class)->startup (app); +} + + +static void +xscreensaver_app_activate (GApplication *app) +{ + XScreenSaverWindow *win = + g_object_new (XSCREENSAVER_WINDOW_TYPE, "application", app, NULL); + win->state.debug_p = XSCREENSAVER_APP (app)->cmdline_debug_p; + gtk_widget_show_all (GTK_WIDGET (win)); + gtk_window_present (GTK_WINDOW (win)); +} + + +static void +xscreensaver_app_open (GApplication *app, + GFile **files, gint n_files, + const gchar *hint) +{ + GList *windows = gtk_application_get_windows (GTK_APPLICATION (app)); + if (windows) + gtk_window_present (GTK_WINDOW (windows->data)); + else + xscreensaver_app_activate (app); +} + + +static int +opts_cb (GApplication *app, GVariantDict *opts, gpointer data) +{ + if (g_variant_dict_contains (opts, "version")) { + fprintf (stderr, "%s\n", screensaver_id+4); + return 0; + } else if (g_variant_dict_contains (opts, "debug")) { + XSCREENSAVER_APP (app)->cmdline_debug_p = TRUE; + return -1; + } else { + return -1; + } +} + + +static void +xscreensaver_app_class_init (XScreenSaverAppClass *class) +{ + G_APPLICATION_CLASS (class)->startup = xscreensaver_app_startup; + G_APPLICATION_CLASS (class)->activate = xscreensaver_app_activate; + G_APPLICATION_CLASS (class)->open = xscreensaver_app_open; } +static XScreenSaverApp * +xscreensaver_app_new (void) +{ + XScreenSaverApp *app = g_object_new (XSCREENSAVER_APP_TYPE, + "application-id", + "org.jwz.xscreensaver.settings", + NULL); + + g_application_add_main_option (G_APPLICATION (app), "version", 'v', + G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, + "Print the version number", + NULL); + g_application_add_main_option (G_APPLICATION (app), "debug", 0, + G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, + "Print diagnostics to stderr", + NULL); + g_signal_connect (app, "handle-local-options", G_CALLBACK (opts_cb), app); + return app; +} + + +int +main (int argc, char *argv[]) +{ + char *s; + progname = argv[0]; + s = strrchr (progname, '/'); + if (s) progname = s+1; + g_log_set_default_handler (g_logger, NULL); + g_log_set_writer_func (g_other_logger, NULL, NULL); + return g_application_run (G_APPLICATION (xscreensaver_app_new()), + argc, argv); +} + + + #endif /* HAVE_GTK -- whole file */ diff --git a/driver/demo.ui b/driver/demo.ui new file mode 100644 index 00000000..acd53609 --- /dev/null +++ b/driver/demo.ui @@ -0,0 +1,2680 @@ + + + + diff --git a/driver/dpms.c b/driver/dpms.c index 18a59b62..fe5e2454 100644 --- a/driver/dpms.c +++ b/driver/dpms.c @@ -1,5 +1,5 @@ /* dpms.c --- syncing the X Display Power Management System values - * xscreensaver, Copyright © 2001-2021 Jamie Zawinski + * xscreensaver, Copyright © 2001-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -107,8 +107,10 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) Bool verbose_p = p->verbose_p; static Bool warned_p = False; - /* If the monitor is currently powered off, defer any changes until - we are next called while it is powered on. */ + /* If the monitor is currently powered off, defer any changes until we are + next called while it is powered on. Making changes to the DPMS settings + can have the side-effect of powering the monitor back on. + */ if (! monitor_powered_on_p (dpy)) { if (verbose_p > 1) diff --git a/driver/fade.c b/driver/fade.c index 61160883..885ccc44 100644 --- a/driver/fade.c +++ b/driver/fade.c @@ -450,14 +450,14 @@ colormap_fade (XtAppContext app, Display *dpy, int status = -1; Colormap *window_cmaps = 0; int i, j, k; - int cmaps_per_screen = 5; - int nscreens = ScreenCount(dpy); - int ncmaps = nscreens * cmaps_per_screen; + unsigned int cmaps_per_screen = 5; + unsigned int nscreens = ScreenCount(dpy); + unsigned int ncmaps = nscreens * cmaps_per_screen; Colormap *fade_cmaps = 0; Bool installed = False; - int total_ncolors; + unsigned int total_ncolors; XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors; - int screen; + unsigned int screen; window_cmaps = (Colormap *) calloc(sizeof(Colormap), nwindows); if (!window_cmaps) abort(); diff --git a/driver/gresource.xml b/driver/gresource.xml new file mode 100644 index 00000000..345faddc --- /dev/null +++ b/driver/gresource.xml @@ -0,0 +1,7 @@ + + + + demo.ui + prefs.ui + + diff --git a/driver/passwd-pwent.c b/driver/passwd-pwent.c index b6c74de7..c5680637 100644 --- a/driver/passwd-pwent.c +++ b/driver/passwd-pwent.c @@ -1,5 +1,5 @@ /* passwd-pwent.c --- verifying typed passwords with the OS. - * xscreensaver, Copyright © 1993-2021 Jamie Zawinski + * xscreensaver, Copyright © 1993-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -163,6 +163,7 @@ get_encrypted_passwd (const char *user) result = strdup(p->pw_passwd); } +# ifdef HAVE_HPUX_PASSWD /* The manual for passwd(4) on HPUX 10.10 says: Password aging is put in effect for a particular user if his @@ -173,6 +174,9 @@ get_encrypted_passwd (const char *user) So this means that passwd->pw_passwd isn't simply a string of cyphertext, it might have trailing junk. So, if there is a comma in the string, and that comma is beyond position 13, terminate the string before the comma. + + This behavior can break other systems where comma separated data is + significant, such as argon2 passwords on NetBSD. */ if (result && strlen(result) > 13) { @@ -180,6 +184,7 @@ get_encrypted_passwd (const char *user) if (s) *s = 0; } +# endif /* HAVE_HPUX_PASSWD */ /* We only issue this warning in non-verbose mode if not compiled with support for PAM. If we're using PAM, it's common for pwent passwords diff --git a/driver/prefs.ui b/driver/prefs.ui new file mode 100644 index 00000000..a6e4e2ec --- /dev/null +++ b/driver/prefs.ui @@ -0,0 +1,518 @@ + + + + diff --git a/driver/prefsw.c b/driver/prefsw.c index 7e347074..64da1eb5 100644 --- a/driver/prefsw.c +++ b/driver/prefsw.c @@ -80,22 +80,6 @@ chase_symlinks (const char *file) } -static Bool -i_am_a_nobody (uid_t uid) -{ - struct passwd *p; - - p = getpwnam ("nobody"); - if (! p) p = getpwnam ("noaccess"); - if (! p) p = getpwnam ("daemon"); - - if (! p) /* There is no nobody? */ - return False; - - return (uid == p->pw_uid); -} - - const char * init_file_name (void) { @@ -103,32 +87,7 @@ init_file_name (void) if (!file) { - uid_t uid = getuid (); const char *home = getenv("HOME"); - - if (i_am_a_nobody (uid) || !home || !*home) - { - /* If we're running as nobody, then use root's .xscreensaver file - (since ~root/.xscreensaver and ~nobody/.xscreensaver are likely - to be different -- without this, xscreensaver-settings would - appear to have no effect when the luser is running as root.) - */ - struct passwd *p = getpwuid (uid); - if (!p || !p->pw_name || !*p->pw_name) - { - fprintf (stderr, "%s: couldn't get user info of uid %d\n", - blurb(), getuid ()); - } - else if (!p->pw_dir || !*p->pw_dir) - { - fprintf (stderr, "%s: couldn't get home directory of \"%s\"\n", - blurb(), (p->pw_name ? p->pw_name : "???")); - } - else - { - home = p->pw_dir; - } - } if (home && *home) { const char *name = ".xscreensaver"; @@ -155,32 +114,29 @@ static const char * init_file_tmp_name (void) { static char *file = 0; - if (!file) - { - const char *name = init_file_name(); - const char *suffix = ".tmp"; + const char *name = init_file_name(); + char *n2 = chase_symlinks (name); + if (n2) name = n2; - char *n2 = chase_symlinks (name); - if (n2) name = n2; + if (file) free (file); - if (!name || !*name) - file = ""; - else - { - file = (char *) malloc(strlen(name) + strlen(suffix) + 2); - strcpy(file, name); - strcat(file, suffix); - } - - if (n2) free (n2); + if (!name || !*name) + file = 0; + else + { + file = (char *) malloc(strlen(name) + 20); + sprintf (file, "%s.%08lX", name, (random() % 0xFFFFFFFF)); } + if (n2) free (n2); + if (file && *file) return file; else return 0; } + static const char * const prefs[] = { "timeout", "cycle", @@ -226,6 +182,7 @@ static const char * const prefs[] = { "textProgram", "textURL", "dialogTheme", + "settingsGeom", "", "programs", "", @@ -293,7 +250,7 @@ static void line_handler (int lineno, { struct parser_closure *c = (struct parser_closure *) closure; saver_preferences *p = c->prefs; - if (!p->db) abort(); + if (!p->db) return; /* Not X11, Wayland */ handle_entry (&p->db, key, val, c->file, lineno); } @@ -506,8 +463,6 @@ write_init_file (Display *dpy, */ char *visual_name; char *programs; - Bool overlay_stderr_p; - char *stderr_font; FILE *out; if (!name) goto END; @@ -535,9 +490,7 @@ write_init_file (Display *dpy, /* Give the new .xscreensaver file the same permissions as the old one; except ensure that it is readable and writable by owner, and not - executable. Extra hack: if we're running as root, make the file - be world-readable (so that the daemon, running as "nobody", will - still be able to read it.) + executable. */ if (stat(name, &st) == 0) { @@ -545,9 +498,6 @@ write_init_file (Display *dpy, mode |= S_IRUSR | S_IWUSR; /* read/write by user */ mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); /* executable by none */ - if (getuid() == (uid_t) 0) /* read by group/other */ - mode |= S_IRGRP | S_IROTH; - if (fchmod (fileno(out), mode) != 0) { char *buf = (char *) malloc(1024 + strlen(name)); @@ -559,11 +509,9 @@ write_init_file (Display *dpy, } } - /* Kludge, since these aren't in the saver_preferences struct... */ + /* Kludge, since this isn't in the saver_preferences struct... */ visual_name = get_string_resource (dpy, "visualID", "VisualID"); programs = 0; - overlay_stderr_p = get_boolean_resource (dpy, "overlayStderr", "Boolean"); - stderr_font = get_string_resource (dpy, "font", "Font"); i = 0; { @@ -646,6 +594,7 @@ write_init_file (Display *dpy, CHECK("loadURL") continue; /* don't save */ CHECK("newLoginCommand") continue; /* don't save */ CHECK("dialogTheme") type = pref_str, s = p->dialog_theme; + CHECK("settingsGeom") type = pref_str, s = p->settings_geom; CHECK("nice") type = pref_int, i = p->nice_inferior; CHECK("memoryLimit") continue; /* don't save */ CHECK("fade") type = pref_bool, b = p->fade_p; @@ -657,8 +606,6 @@ write_init_file (Display *dpy, CHECK("ignoreUninstalledPrograms") type = pref_bool, b = p->ignore_uninstalled_p; - CHECK("font") type = pref_str, s = stderr_font; - CHECK("dpmsEnabled") type = pref_bool, b = p->dpms_enabled_p; CHECK("dpmsQuickOff") type = pref_bool, b = p->dpms_quickoff_p; CHECK("dpmsStandby") type = pref_time, t = p->dpms_standby; @@ -692,7 +639,8 @@ write_init_file (Display *dpy, CHECK("programs") type = pref_str, s = programs; CHECK("pointerHysteresis")type = pref_int, i = p->pointer_hysteresis; - CHECK("overlayStderr") type = pref_bool, b = overlay_stderr_p; + CHECK("font") continue; /* don't save */ + CHECK("overlayStderr") continue; /* don't save */ CHECK("overlayTextBackground") continue; /* don't save */ CHECK("overlayTextForeground") continue; /* don't save */ CHECK("bourneShell") continue; /* don't save */ @@ -759,7 +707,6 @@ write_init_file (Display *dpy, fprintf(out, "\n"); if (visual_name) free(visual_name); - if (stderr_font) free(stderr_font); if (programs) free(programs); if (fclose(out) == 0) @@ -926,6 +873,7 @@ load_init_file (Display *dpy, saver_preferences *p) p->new_login_command = get_string_resource(dpy, "newLoginCommand", "Command"); p->dialog_theme = get_string_resource(dpy, "dialogTheme", "String"); + p->settings_geom = get_string_resource(dpy, "settingsGeom", "String"); p->auth_warning_slack = get_integer_resource(dpy, "authWarningSlack", "Integer"); @@ -1135,7 +1083,7 @@ format_command (const char *cmd, Bool wrap_p) { int tab = 30; int col = tab; - char *cmd2 = (char *) calloc (1, 2 * (strlen (cmd) + 1)); + char *cmd2 = (char *) calloc (1, 2 * (strlen (cmd) + 10)); const char *in = cmd; char *out = cmd2; while (*in) @@ -1172,6 +1120,14 @@ format_command (const char *cmd, Bool wrap_p) while (out > cmd2 && isspace (out[-1])) *(--out) = 0; + /* In version 6.05, the defaults were changed from "-root" to "--root". + If anything in .xscreensaver still ends with "-root", silently change + it, so that the "Reset to Defaults" button is enabled/disabled as + appropriate, and doesn't think the command differs from the default. + */ + if (out > cmd2+7 && !strcmp (out-6, " -root")) + strcpy (out-6, " --root"); /* malloc had enough slack */ + return cmd2; } diff --git a/driver/subprocs.c b/driver/subprocs.c index 6e522d30..6385a1f1 100644 --- a/driver/subprocs.c +++ b/driver/subprocs.c @@ -1,5 +1,5 @@ /* subprocs.c --- choosing, spawning, and killing screenhacks. - * xscreensaver, Copyright © 1991-2021 Jamie Zawinski + * xscreensaver, Copyright © 1991-2022 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -461,6 +461,16 @@ xt_sigterm_handler (XtPointer data, XtSignalId *id) fprintf (stderr, "%s: %s: unblanking\n", blurb(), signal_name (sigterm_received)); + /* We are in the process of shutting down and are about to exit, + so don't accidentally re-launch hacks. */ + si->terminating_p = True; + + if (si->watchdog_id) + { + XtRemoveTimeOut (si->watchdog_id); + si->watchdog_id = 0; + } + /* Kill before unblanking, to stop drawing as soon as possible. */ for (i = 0; i < si->nscreens; i++) { diff --git a/driver/types.h b/driver/types.h index 8fa7c8e7..6eca284d 100644 --- a/driver/types.h +++ b/driver/types.h @@ -105,6 +105,7 @@ struct saver_preferences { char *load_url_command; /* How one loads URLs. */ char *new_login_command; /* Command for the "New Login" button. */ char *dialog_theme; /* Color scheme on the unlock dialog */ + char *settings_geom; /* Saved positions of the settings windows */ int auth_warning_slack; /* Don't warn about login failures if they all happen within this many seconds of @@ -139,6 +140,8 @@ struct saver_info { Bool demoing_p; /* Whether we are demoing a single hack (without UI.) */ Bool emergency_p; /* Restarted because of a crash */ + Bool terminating_p; /* In the process of shutting down */ + XtIntervalId watchdog_id; /* Timer to implement `prefs.watchdog */ int selection_mode; /* Set to -1 if the NEXT ClientMessage has just diff --git a/driver/windows.c b/driver/windows.c index c92486aa..cd47f4f8 100644 --- a/driver/windows.c +++ b/driver/windows.c @@ -959,7 +959,7 @@ watchdog_timer (XtPointer closure, XtIntervalId *id) { saver_info *si = (saver_info *) closure; saver_preferences *p = &si->prefs; - Bool running_p, on_p; + Bool running_p, on_p, terminating_p; /* If the DPMS settings on the server have changed, change them back to what ~/.xscreensaver says they should be. */ @@ -972,6 +972,7 @@ watchdog_timer (XtPointer closure, XtIntervalId *id) running_p = any_screenhacks_running_p (si); on_p = monitor_powered_on_p (si->dpy); + terminating_p = si->terminating_p; if (running_p && !on_p) { int i; @@ -983,6 +984,11 @@ watchdog_timer (XtPointer closure, XtIntervalId *id) kill_screenhack (&si->screens[i]); /* Do not clear current_hack here. */ } + else if (terminating_p) + { + /* If we are in the process of shutting down and are about to exit, + don't re-launch anything just because the monitor came back on. */ + } else if (!running_p && on_p) { /* If the hack number is set but no hack is running, it is because the diff --git a/driver/xscreensaver-auth.c b/driver/xscreensaver-auth.c index b5cce926..0a1cc612 100644 --- a/driver/xscreensaver-auth.c +++ b/driver/xscreensaver-auth.c @@ -167,6 +167,66 @@ oom_assassin_immunity (void) #endif /* HAVE_PROC_OOM */ +#ifndef HAVE_DPMS_EXTENSION +# define dpms_init (dpy) /** */ + +#else /* HAVE_DPMS_EXTENSION */ + +# include +# include + +static int +ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) +{ + return 0; +} + +/* When XScreenSaver first launches, power on the monitor and disable DPMS. + The DPMS settings will be re-written when 'xscreensaver-gfx' launches for + the first time to blank the screen, and will be re-enabled if that is what + is configured in ~/.xscreensaver. + + Without this, if the server's default DPMS timeouts are different than, and + less than, the .xscreensaver file's 'timeout' and 'dpmsStandby' the monitor + will already be powered down when 'xscreensaver-gfx' launches for the first + time, and it will never change them, as it can't touch those settings if + the monitor is already powered off. + + It would be better for us to call sync_server_dpms_settings() here, but + that requires a full 'saver_preferences' struct. Once 'xscreensaver-gfx' + is launched, it will correct things. + + The only way this behaves oddly is if the user has set their 'dpmsStandby' + to less than their 'timeout', but that would be weird, right? That + probably shouldn't even be permitted (though currently it is). + + This is in 'xscreensaver-auth' because that's run at startup with either + --splash or --init, long before 'xscreensaver-gfx' is run for the first + time; and putting this code into 'xscreensaver' would violate the principle + of linking only the bare minimum into the daemon itself. + */ +static void +dpms_init (Display *dpy) +{ + int ev, err; + XErrorHandler old_handler; + XSync (dpy, False); + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + XSync (dpy, False); + + if (DPMSQueryExtension (dpy, &ev, &err)) + { + DPMSForceLevel (dpy, DPMSModeOn); + DPMSDisable (dpy); + } + XSetScreenSaver (dpy, 0, 0, 0, 0); + + XSync (dpy, False); + XSetErrorHandler (old_handler); +} +#endif /* HAVE_DPMS_EXTENSION */ + + int main (int argc, char **argv) { @@ -273,12 +333,9 @@ main (int argc, char **argv) if (!splash_p && !init_p) lock_priv_init (); - if (!splash_p && init_p) - exit (0); - disavow_privileges (); - if (!splash_p) + if (!splash_p && !init_p) lock_init (); /* Setting the locale is necessary for XLookupString to return multi-byte @@ -316,7 +373,14 @@ main (int argc, char **argv) if (xsync_p) XSynchronize (dpy, True); init_xscreensaver_atoms (dpy); - if (splash_p) + if (splash_p == 1 || init_p) + dpms_init (dpy); + + if (!splash_p && init_p) + { + exit (0); + } + else if (splash_p) { /* Settings button is disabled with --splash --splash */ xscreensaver_splash (root_widget, splash_p > 1); diff --git a/driver/xscreensaver-auth.man b/driver/xscreensaver-auth.man index 16556026..8be0f7cb 100644 --- a/driver/xscreensaver-auth.man +++ b/driver/xscreensaver-auth.man @@ -3,7 +3,7 @@ xscreensaver - extensible screen saver and screen locking framework .SH SYNOPSIS .B xscreensaver-auth -[\-display \fIhost:display.screen\fP] +[\-\-display \fIhost:display.screen\fP] .SH DESCRIPTION The .BR xscreensaver (1) diff --git a/driver/xscreensaver-command.man b/driver/xscreensaver-command.man index a84cbabe..c0301d4f 100644 --- a/driver/xscreensaver-command.man +++ b/driver/xscreensaver-command.man @@ -60,14 +60,14 @@ graphics demo and run a new one (chosen randomly.) This is like either \fI\-\-activate\fP or \fI\-\-cycle\fP, depending on which is more appropriate, except that the graphics hack that will be run is the next one in the list, instead of a randomly-chosen one. In other words, -repeatedly executing -next will cause the xscreensaver process to invoke each -graphics demo sequentially. (Though using the \fI\-\-settings\fP option is -probably an easier way to accomplish that.) +repeatedly executing \-\-next will cause the xscreensaver process to invoke +each graphics demo sequentially. (Though using the \fI\-\-settings\fP option +is probably an easier way to accomplish that.) .TP 8 .B \-\-prev This is like \fI\-\-next\fP, but cycles in the other direction. .TP 8 -.B \-\-select \fInumber\fP +.B \-\-select\fP \fInumber\fP Like \fI\-\-activate\fP, but runs the \fIN\fPth element in the list of hacks. By knowing what is in the \fIprograms\fP list, and in what order, you can use this to activate the screensaver with a particular graphics demo. (The first @@ -94,10 +94,8 @@ to lock things down quickly. Causes the xscreensaver process to exit gracefully. This does nothing if the display is currently locked. .B Warning: -never use \fIkill -9\fP with \fIxscreensaver\fP while the screensaver is -active. If you are using a virtual root window manager, that can leave -things in an inconsistent state, and you may need to restart your window -manager to repair the damage. +never use \fIkill -9\fP with \fIxscreensaver\fP. That can leave things in an +inconsistent state, and you may need to log out to repair the damage. .TP 8 .B \-\-restart Causes the screensaver process to exit and then restart with the same command @@ -217,7 +215,7 @@ and related tools can always be found at https://www.jwz.org/xscreensaver/ .BR xscreensaver\-settings (1), .BR xset (1) .SH COPYRIGHT -Copyright \(co 1992-2021 by Jamie Zawinski. +Copyright \(co 1992-2022 by Jamie Zawinski. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that @@ -226,6 +224,6 @@ supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. .SH AUTHOR -Jamie Zawinski , 13-aug-1992. +Jamie Zawinski . Please let me know if you find any bugs or make any improvements. diff --git a/driver/xscreensaver-gfx.man b/driver/xscreensaver-gfx.man index 7b209ac3..52e22712 100644 --- a/driver/xscreensaver-gfx.man +++ b/driver/xscreensaver-gfx.man @@ -3,7 +3,7 @@ xscreensaver - extensible screen saver and screen locking framework .SH SYNOPSIS .B xscreensaver-gfx -[\-display \fIhost:display.screen\fP] +[\-\-display \fIhost:display.screen\fP] .SH DESCRIPTION The .BR xscreensaver (1) diff --git a/driver/xscreensaver-settings.man b/driver/xscreensaver-settings.man index 2ed70af9..29de8288 100644 --- a/driver/xscreensaver-settings.man +++ b/driver/xscreensaver-settings.man @@ -3,9 +3,9 @@ xscreensaver-settings - configure and control the xscreensaver daemon .SH SYNOPSIS .B xscreensaver\-settings -[\-display \fIhost:display.screen\fP] -[\-prefs] -[\-debug] +[\-\-display \fIhost:display.screen\fP] +[\-\-prefs] +[\-\-debug] .SH DESCRIPTION The \fIxscreensaver\-settings\fP program is a graphical front-end for setting the parameters used by the @@ -23,20 +23,20 @@ All of these commands are on either the \fBFile\fP or \fBHelp\fP menus: Activates the background \fIxscreensaver\fP daemon, which will then run a demo at random. This is the same as running .BR xscreensaver\-command (1) -with the \fI\-activate\fP option. +with the \fI\-\-activate\fP option. .TP 4 .B Lock Screen Now Just like \fBBlank Screen Now\fP, except the screen will be locked as well (even if it is not configured to lock all the time.) This is the same as running .BR xscreensaver\-command (1) -with the \fI\-lock\fP option. +with the \fI\-\-lock\fP option. .TP 4 .B Kill Daemon If the xscreensaver daemon is running on this screen, kill it. This is the same as running .BR xscreensaver\-command (1) -with the \fI\-exit\fP option. +with the \fI\-\-exit\fP option. .TP 4 .B Restart Daemon If the xscreensaver daemon is running on this screen, kill it. @@ -293,16 +293,16 @@ file, or the X resource database. .I xscreensaver\-settings accepts the following command line options. .TP 8 -.B \-display \fIhost:display.screen\fP +.B \-\-display \fIhost:display.screen\fP The X display to use. The \fIxscreensaver\-settings\fP program will open its window on that display, and also control the \fIxscreensaver\fP daemon that is managing that same display. .TP 8 -.B \-prefs +.B \-\-prefs Start up with the \fBAdvanced\fP tab selected by default instead of the \fBDisplay Modes\fP tab. .TP 8 -.B \-debug +.B \-\-debug Causes lots of diagnostics to be printed on stderr. .PP The \fIxscreensaver\fP and \fIxscreensaver\-settings\fP processes must run @@ -343,7 +343,7 @@ and a FAQ can always be found at https://www.jwz.org/xscreensaver/ .BR xscreensaver\-getimage\-video (MANSUFFIX), .BR xscreensaver\-text (MANSUFFIX) .SH COPYRIGHT -Copyright \(co 1992-2021 by Jamie Zawinski. +Copyright \(co 1992-2022 by Jamie Zawinski. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that @@ -352,6 +352,6 @@ supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. .SH AUTHOR -Jamie Zawinski , 13-aug-1992. +Jamie Zawinski . Please let me know if you find any bugs or make any improvements. diff --git a/driver/xscreensaver-systemd.c b/driver/xscreensaver-systemd.c index 355fcf47..9e8d6119 100644 --- a/driver/xscreensaver-systemd.c +++ b/driver/xscreensaver-systemd.c @@ -206,6 +206,19 @@ * ***************************************************************************** * + * MPV 0.33+, I think: + * + * The developer had a hissy fit and removed "xdg-screensaver" support: + * + * https://github.com/mpv-player/mpv/commit/c498b2846af0ee8835b9144c9f6893568a4e49c6 + * + * So now I guess you're back to figuring out how to add a "heartbeat" + * command to have MPV periodically call "xscreensaver-command -reset". + * Good luck with that. Maybe you should just use VLC instead. + * + * + ***************************************************************************** + * * VLC 3.0.16-1, Raspbian 11.1 & Debian 11.3: * * Sends "Inhibit" to the first of these targets that exists at launch: diff --git a/driver/xscreensaver-systemd.man b/driver/xscreensaver-systemd.man index ba08bec9..1904c8ce 100644 --- a/driver/xscreensaver-systemd.man +++ b/driver/xscreensaver-systemd.man @@ -64,7 +64,9 @@ only inhibits for the first few seconds. .PP Firefox does not have either of these problems. .SS MPLAYER (2:1.4) -Makes no attempt to inhibit the screen saver. Use VLC or MPV instead. +Makes no attempt to inhibit the screen saver. Use VLC instead. +.SS MPV (0.33) +Makes no attempt to inhibit the screen saver. Use VLC instead. .SS VARIOUS Most programs fail to inhibit screen blanking if they crash or are killed while playing. We try to detect when this has happened and auto-uninhibit, diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 01834e94..983a10dd 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -2364,7 +2364,8 @@ main (int argc, char **argv) { logfile = argv[++i]; if (!logfile) goto HELP; - verbose_p = cmdline_verbose_p = cmdline_verbose_val = True; + if (! verbose_p) /* might already be -vv */ + verbose_p = cmdline_verbose_p = cmdline_verbose_val = True; } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "-dpy") || diff --git a/driver/xscreensaver.man b/driver/xscreensaver.man index de2aac64..89364822 100644 --- a/driver/xscreensaver.man +++ b/driver/xscreensaver.man @@ -58,20 +58,12 @@ The .BR xscreensaver\-settings (1) program is where you configure if and when your monitor should power off. It saves the settings in your \fI~/.xscreensaver\fP file. +Do not use +.BR xset (1) +to manually change the power management settings, that won't work. -If the power management section is grayed out in the -.BR xscreensaver\-settings (1) -window, then that means that your X server does not support -the XDPMS extension, and so control over the monitor's power state -is not available. - -When the monitor is powered down, the display hacks are stopped +When the monitor is powered down, the display hacks will stop running (though it may take a minute or two for XScreenSaver to notice). - -Note: if you use -.BR xset (1) -to change the power management settings, XScreenSaver will override those -changes. Whatever is in the \fI~/.xscreensaver\fP file takes precedence. .SH LAPTOP LIDS If your system uses .BR systemd (1) @@ -183,7 +175,7 @@ now: .br "\fIHardware / Power Management / Suspend session\fP" .br -"\fIHardware / Power Management / Laptop lid closed => Do Nothing\fP" +"\fIHardware / Power Management / Laptop lid closed" = Do Nothing\fP If there are multiple tabs, you may to change these settings on all three of them: "On AC power", "Battery" and "Low Battery". @@ -267,6 +259,14 @@ these lines: Comment: XScreenSaver .sp .fi +.SS LAPTOP LIDS WITHOUT SYSTEMD +BSD systems or other systems without +.BR systemd (1) +or +.BR elogind (8) +might have luck by adding "\fIxscreensaver\-command \-\-suspend\fP" to +some appropriate spot in \fI/etc/acpi/events/anything\fP or in +\fI/etc/acpi/handler.sh\fP, if those files exist. .SS LAUNCHING XSCREENSAVER FROM GDM You can run \fIxscreensaver\fP from your .BR gdm (1) @@ -309,14 +309,6 @@ and There might be a way to accomplish this with other display managers. It's a mystery! -.SS LAPTOP LIDS WITHOUT SYSTEMD -BSD systems or other systems without -.BR systemd (1) -or -.BR elogind (8) -might have luck by adding "\fIxscreensaver\-command \-\-suspend\fP" to -some appropriate spot in \fI/etc/acpi/events/anything\fP or in -\fI/etc/acpi/handler.sh\fP, if those files exist. .SH THE WAYLAND PROBLEM Wayland is a completely different window system that is intended to replace X11. After 14+ years of trying, some Linux distros have finally begun @@ -435,6 +427,16 @@ You can disable the OOM-killer entirely with: echo vm.overcommit_memory = 2 >> /etc/sysctl.conf .sp .fi +In addition to the kernel's OOM-killer, +.BR systemd (1) +has its own. The included \fIxscreensaver.service\fP file attempts to +evade it, but you may want to just turn it off anyway: +.nf +.sp + sudo systemctl disable --now systemd-oomd + sudo systemctl mask systemd-oomd +.sp +.fi .SS X SERVER ACCESS IS GAME OVER X11's security model is all-or-nothing. If a program can connect to your X server at all, either locally or over the network, it can log all of your diff --git a/driver/xscreensaver.ui b/driver/xscreensaver.ui deleted file mode 100644 index c04bd75d..00000000 --- a/driver/xscreensaver.ui +++ /dev/null @@ -1,3060 +0,0 @@ - - - - - 720 - 1 - 15 - 1 - 0 - 1 - - - 720 - 0 - 15 - 1 - 0 - 0 - - - 720 - 0 - 15 - 1 - 0 - 0 - - - 1440 - 0 - 15 - 1 - 0 - 0 - - - 1440 - 0 - 15 - 1 - 0 - 0 - - - 1440 - 0 - 15 - 1 - 0 - 0 - - - 10 - 0 - 1 - 1 - 0 - 0 - - - - - - - - Disable Screen Saver - - - Blank Screen Only - - - Only One Screen Saver - - - Random Screen Saver - - - Same Random Savers - - - - - - - - - - - Default - - - - - - - - - - - - - - - Any - - - Best - - - Default - - - Default-N - - - GL - - - TrueColor - - - PseudoColor - - - StaticGray - - - GrayScale - - - DirectColor - - - Color - - - Gray - - - Mono - - - - - - - - - file - _File - - - - - - activate_action - _Blank Screen Now - - - - - - lock_action - _Lock Screen Now - - - - - - kill_action - _Kill Daemon - - - - - - restart_action - _Restart Daemon - - - - - - exit_action - _Quit - - - - - - help - _Help - - - - - about_action - _About... - - - - - - doc_action - _Documentation... - - - - - - - - - - - - - - - - - - - - - - - - XScreenSaver - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - True - False - 5 - - - True - GTK_PACK_DIRECTION_LTR - GTK_PACK_DIRECTION_LTR - - - 0 - False - False - - - - - 8 - True - False - 0 - - - True - True - True - True - GTK_POS_TOP - False - False - - - - 10 - True - 2 - 2 - False - 0 - 0 - - - True - 3 - 4 - False - 2 - 0 - - - True - _Cycle After - True - False - GTK_JUSTIFY_RIGHT - False - False - 1 - 0.5 - 8 - 0 - cycle_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 1 - 2 - 1 - 2 - fill - - - - - - True - Whether a password should be required to un-blank the screen. - False - False - - - True - True - _Lock Screen After - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - - Lock Screen - - - - - - - 0 - 2 - 2 - 3 - fill - - - - - - True - How long before the screen saver activates. - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment1 - - - - - - - - - - - - 2 - 3 - 0 - 1 - fill - - - - - - True - How long after the screen blanks until a password will be required. - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment2 - - - - - - - - - - - - - Lock Screen After - - - - - 2 - 3 - 2 - 3 - 10 - fill - - - - - - True - How long each display mode should run before choosing a new one (in Random mode.) - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment3 - - - - - - - - - - - - 2 - 3 - 1 - 2 - fill - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 8 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 3 - 4 - 2 - 3 - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 8 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 3 - 4 - 1 - 2 - - - - - - True - _Blank After - True - False - GTK_JUSTIFY_RIGHT - False - False - 1 - 0.5 - 8 - 0 - timeout_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 1 - 2 - 0 - 1 - fill - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 8 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 3 - 4 - 0 - 1 - - - - - - 0 - 1 - 1 - 2 - fill - fill - - - - - True - GTK_BUTTONBOX_SPREAD - 30 - - - True - Demo the selected screen saver in full-screen mode (click the mouse to return.) - True - True - _Preview - True - GTK_RELIEF_NORMAL - True - - - - - - True - Customization and explanation of the selected screen saver. - True - True - _Settings... - True - GTK_RELIEF_NORMAL - True - - - - - - 1 - 2 - 1 - 2 - fill - fill - - - - - 10 - True - False - 0 - - - True - False - 0 - - - True - _Mode: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - mode_menu - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - 0 - False - False - - - - - True - True - False - mode_menu_model - - - - - - - 0 - - - - - 4 - True - True - - - - - 10 - False - True - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - True - True - False - True - False - True - False - False - False - - - - - 0 - True - True - - - - - True - True - 0 - - - True - False - 0 - - - True - Run the next screen saver in the list in full-screen mode (click the mouse to return.) - True - GTK_RELIEF_NORMAL - True - - - - True - GTK_ARROW_DOWN - GTK_SHADOW_OUT - 0.5 - 0.5 - 0 - 0 - - - - - 0 - False - False - - - - - True - Run the previous screen saver in the list in full-screen mode (click the mouse to return.) - True - GTK_RELIEF_NORMAL - True - - - - True - GTK_ARROW_UP - GTK_SHADOW_OUT - 0.5 - 0.5 - 0 - 0 - - - - - 0 - False - False - - - - - 0 - False - False - - - - - 0 - False - True - GTK_PACK_END - - - - - 0 - 1 - 0 - 1 - fill - - - - - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - - - 5 - True - False - 5 - - - True - True - True - False - GTK_POS_BOTTOM - False - False - - - 8 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - 0.5 - 0.5 - 1.777777 - False - - - True - - - - - False - True - - - - - True - preview - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - True - No Preview -Available - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - False - True - - - - - True - no preview - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - True - Not -Installed - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - False - True - - - - - True - not installed - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - True - Very few (or no) screen savers appear to be available. - -This probably means that the "xscreensaver-extras" and -"xscreensaver-gl-extras" packages are not installed. - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - False - True - - - - - True - nothing - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.0 - 0 - 0 - PANGO_ELLIPSIZE_NONE - 72 - False - 0 - - - - - - 0 - False - True - - - - - - True - - False - False - GTK_JUSTIFY_CENTER - True - False - 0.5 - 0.0 - 0 - 0 - PANGO_ELLIPSIZE_NONE - 72 - False - 0 - - - - - - 0 - False - True - - - - - - - - - True - Description - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 1 - 2 - 0 - 1 - 6 - expand|shrink|fill - expand|shrink|fill - - - - - False - True - - - - - True - _Display Modes - True - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - notebook - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - True - 2 - 2 - True - 0 - 0 - - - 10 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - - - 8 - True - False - 8 - - - True - screensaver-snap.png - 0 - 0 - 4 - 8 - - - 0 - False - False - - - - - True - False - 0 - - - True - Whether the image-manipulating modes should be allowed to operate on an image of your desktop. - True - Grab Desktop _Images - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 0 - False - False - - - - - True - Whether the image-manipulating modes should operate on images captured from the system's video input (if there is one.) - True - Grab _Video Frames - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 0 - False - False - - - - - True - Whether the image-manipulating modes should load image files. - True - Choose _Random Image: - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - 0 - False - False - - - - - True - False - 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 8 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - True - The local directory, RSS feed or Atom feed from which images will be randomly chosen. - True - True - True - 0 - - True - * - False - - - - - - - - - 2 - True - True - - - - - True - True - _Browse - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 0 - False - False - - - - - True - Local directory, or URL of RSS or Atom feed. - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 20 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 0 - True - True - - - - - - - True - Image Manipulation - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 0 - 1 - 0 - 1 - - - - - 10 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - - - 8 - True - False - 8 - - - - 0 - False - False - - - - - True - 5 - 3 - False - 2 - 2 - - - True - Text-displaying modes will display the text typed here. - True - _Text - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - - 0 - 1 - 1 - 2 - fill - - - - - - True - Text-displaying modes will display the contents of this file. - True - Text _file - True - GTK_RELIEF_NORMAL - True - False - False - True - text_radio - - - - - - - - 0 - 1 - 2 - 3 - fill - - - - - - True - Text-displaying modes will display the output of this program. - True - _Program - True - GTK_RELIEF_NORMAL - True - False - False - True - text_radio - - - - - - - - - 0 - 1 - 3 - 4 - fill - - - - - - True - Text-displaying modes will display the contents of this URL (HTML or RSS). - True - _URL - True - GTK_RELIEF_NORMAL - True - False - False - True - text_radio - - - - - - - - 0 - 1 - 4 - 5 - fill - - - - - - True - Text-displaying modes will display the local host name, date, and time. - True - _Host Name and Time - True - GTK_RELIEF_NORMAL - True - True - False - True - text_radio - - - - 0 - 3 - 0 - 1 - fill - - - - - - True - Text-displaying modes will display the contents of this URL (HTML or RSS). - True - True - True - 0 - - True - * - False - - - - - - - - 1 - 3 - 4 - 5 - - - - - - True - True - _Browse - True - GTK_RELIEF_NORMAL - True - - - - - - - 2 - 3 - 2 - 3 - fill - - - - - - True - Text-displaying modes will display the text typed here. - True - True - True - 0 - - True - * - False - - - - - - - - - 1 - 3 - 1 - 2 - - - - - - True - Text-displaying modes will display the output of this program. - True - True - True - 0 - - True - * - False - - - - - - - - - 1 - 2 - 3 - 4 - - - - - - True - True - _Browse - True - GTK_RELIEF_NORMAL - True - - - - - - - 2 - 3 - 3 - 4 - fill - - - - - - True - Text-displaying modes will display the contents of this file. - True - True - True - 0 - - True - * - False - - - - - - - - - 1 - 2 - 2 - 3 - - - - - - 0 - True - True - - - - - - - True - Text Manipulation - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 0 - 1 - 1 - 2 - fill - - - - - 10 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - 8 - True - False - 8 - - - - 0 - False - False - - - - - True - False - 0 - - - True - Whether the monitor should be powered down after a while. - True - _Power Management Enabled - True - GTK_RELIEF_NORMAL - True - True - False - True - - - - - - - - - 0 - False - False - - - - - True - 3 - 3 - False - 2 - 4 - - - True - Stand_by After - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 10 - 0 - dpms_standby_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 0 - 1 - 0 - 1 - fill - - - - - - True - Sus_pend After - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 10 - 0 - dpms_suspend_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 0 - 1 - 1 - 2 - fill - - - - - - True - _Off After - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 10 - 0 - dpms_off_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 0 - 1 - 2 - 3 - fill - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 2 - 3 - 0 - 1 - fill - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 2 - 3 - 1 - 2 - fill - - - - - - True - minutes - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 2 - 3 - 2 - 3 - fill - - - - - - True - How long until the monitor powers down. - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment4 - - - - - - - - - - - - - 1 - 2 - 2 - 3 - - - - - - - True - How long until the monitor goes into power-saving mode. - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment5 - - - - - - - - - - - - - 1 - 2 - 1 - 2 - - - - - - - True - How long until the monitor goes completely black. - True - 15 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment6 - - - - - - - - - - - - - 1 - 2 - 0 - 1 - - - - - - - 0 - False - True - - - - - True - Whether the monitor should be powered off immediately in "Blank Screen Only" mode, regardless of the above power-management timeouts. - True - _Quick Power-off in Blank Only Mode - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - 0 - False - False - - - - - 0 - True - True - - - - - - - True - Display Power Management - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 1 - 2 - 0 - 1 - fill - - - - - 10 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - - - 8 - True - False - 8 - - - True - screensaver-colorselector.png - 0.5 - 0 - 0 - 0 - - - 0 - False - False - - - - - True - False - 0 - - - True - Whether the screen should slowly fade to black when the screen saver activates. - True - Fade to Black when _Blanking - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - 0 - False - False - - - - - True - Whether the screen should slowly fade in from black when the screen saver deactivates. - True - Fade from Black When _Unblanking - True - GTK_RELIEF_NORMAL - True - False - False - True - - - - - - - 0 - False - False - - - - - True - False - 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 3 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - True - F_ade Duration - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - fade_spinbutton - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 14 - False - False - - - - - True - How long it should take for the screen to fade in and out. - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - True - False - adjustment7 - - - - - - - - - - - - - - 4 - False - False - - - - - True - seconds - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - 2 - False - False - - - - - 0 - False - False - - - - - True - - - 8 - False - False - - - - - - - True - False - 0 - - - True - _Theme: - The color scheme to use on the unlock dialog. - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - theme_menu - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - 0 - False - False - - - - - True - True - False - theme_menu_model - - - - - - - 0 - - - - - 4 - True - True - - - - - True - Show the what the unlock dialog will look like. - True - True - _Preview - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 10 - False - True - - - - - - - - 0 - True - True - - - - - - - True - Blanking - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 1 - 2 - 1 - 2 - fill - fill - - - - - False - True - - - - - True - _Advanced - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - notebook - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 5 - GTK_BUTTONBOX_EDGE - 10 - - - True - True - True - gtk-help - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - gtk-close - True - GTK_RELIEF_NORMAL - True - - - - - - 0 - False - True - GTK_PACK_END - - - - - - - dialog1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - True - False - 0 - - - True - GTK_BUTTONBOX_END - - - True - True - True - _Advanced >> - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - _Standard << - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - _Reset to Defaults - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - - - - - - 0 - False - True - GTK_PACK_END - - - - - True - False - 0 - - - True - 0 - 0 - GTK_SHADOW_ETCHED_IN - - - - - - 12 - True - True - True - False - GTK_POS_BOTTOM - False - False - - - - True - False - 0 - - - - - - True - True - GTK_PACK_END - - - - - True - Standard - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - True - 4 - 2 - False - 0 - 0 - - - - 0 - 1 - 0 - 1 - fill - fill - - - - - True - _Command Line: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - cmd_text - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - 1 - 2 - 1 - 2 - fill - - - - - - True - True - True - True - 0 - - True - * - False - - - - - - 1 - 2 - 2 - 3 - - - - - - True - False - 0 - - - True - _Visual: - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 3 - 0 - visual_combo - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - 0 - False - False - - - - - False - True - visual_combo_model - 0 - - - - - - True - True - True - True - 0 - - True - * - False - - - - - 0 - False - False - - - - - 1 - 2 - 3 - 4 - fill - fill - - - - - False - True - - - - - True - Advanced - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - True - Settings - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - - - - 5 - True - True - - - - - True - 0 - 0 - GTK_SHADOW_NONE - - - 5 - True - False - 5 - - - True - True - - False - False - GTK_JUSTIFY_LEFT - True - True - 0 - 0 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - True - True - - - - - True - False - 0 - - - True - True - _Documentation... - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - GTK_PACK_END - - - - - 0 - False - False - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - 0 - False - False - - - - - 0 - True - True - - - - - - adv_button - std_button - reset_button - cancel_button - ok_button - - - diff --git a/hacks/abstractile.man b/hacks/abstractile.man index bbb096ce..ee9f211a 100644 --- a/hacks/abstractile.man +++ b/hacks/abstractile.man @@ -3,8 +3,14 @@ abstractile \- draw abstract mosaic patterns of interlocking tiles .SH SYNOPSIS .B abstractile -[\-sleep \fIseconds\fP] [\-speed \fIint\fP] [\-tile \fItile_mode\fP] -[\-fps] +[\-\-sleep \fIseconds\fP] +[\-\-speed \fIint\fP] +[\-\-tile \fItile_mode\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-fps] .SH DESCRIPTION The \fIabstractile\fP program draws chaotic grids of randomly colored and shaped interlocking tiles. @@ -12,19 +18,32 @@ and shaped interlocking tiles. .I abstractile accepts the following options: .TP 8 -.B \-sleep \fIseconds\fP +.B \-\-sleep \fIseconds\fP Specify the number of seconds to sleep between screens (0-60). .TP 8 -.B \-speed \fIint\fP +.B \-\-speed \fIint\fP A value between 0 and 5 used to specify the speed at which each screen is drawn. .TP 8 -.B \-tile \fItile_mode\fP +.B \-\-tile \fItile_mode\fP The type of tile that is drawn on each screen. Legal values are \fIrandom\fP, \fIflat\fP, \fIthin\fP, \fIoutline\fP, \fIblock\fP, \fIneon\fP, and \fItiled\fP .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. +.TP 8 +.B \-\-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-\-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-\-root +Draw on the root window. +.TP 8 +.B \-\-window\-id \fInumber\fP +Draw on the specified window. .SH ENVIRONMENT .PP .TP 8 @@ -34,14 +53,16 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) .SH COPYRIGHT Copyright \(co 2004 by Steve Sundstrom. Based on examples from the hacks directory of xscreensaver, -Copyright (c) 1997, 1998, 2002 Jamie Zawinski - +Copyright (c) 1997, 1998, 2002 Jamie Zawinski Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, diff --git a/hacks/anemone.man b/hacks/anemone.man index 8c5464ea..c3243466 100644 --- a/hacks/anemone.man +++ b/hacks/anemone.man @@ -3,52 +3,56 @@ anemone \- wiggling tentacles. .SH SYNOPSIS .B anemone -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-arms \fInumber\fP] -[\-finpoints \fInumber\fP] -[\-width \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-arms \fInumber\fP] +[\-\-finpoints \fInumber\fP] +[\-\-width \fInumber\fP] +[\-\-fps] .SH DESCRIPTION Wiggling tentacles. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 40000 (0.04 seconds.). .TP 8 -.B \-arms \fInumber\fP +.B \-\-arms \fInumber\fP Arms. 2 - 500. Default: 128. .TP 8 -.B \-finpoints \fInumber\fP +.B \-\-finpoints \fInumber\fP Tentacles. 3 - 200. Default: 64. .TP 8 -.B \-withdraw \fInumber\fP +.B \-\-withdraw \fInumber\fP Frequency that the arms withdraw. Arms withdraw on randomly generated values between 1 and 11; this value determines the maximum value of that range. So 100 spends a lot of time withdrawn, while 1000,000 tends not to withdraw at all. Default: 1200. .TP 8 -.B \-turnspeed \fInumber\fP +.B \-\-turnspeed \fInumber\fP How fast it turns. At zero, not at all, all they way up to thousands which are very fast indeed. Default: 50. .TP 8 -.B \-width \fInumber\fP +.B \-\-width \fInumber\fP Thickness. 1 - 10. Default: 2. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -59,6 +63,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/anemotaxis.man b/hacks/anemotaxis.man index 7da95666..60671211 100644 --- a/hacks/anemotaxis.man +++ b/hacks/anemotaxis.man @@ -3,15 +3,16 @@ anemotaxis \- directional search on a plane. .SH SYNOPSIS .B anemotaxis -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-distance \fInumber\fP] -[\-sources \fInumber\fP] -[\-searchers \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-distance \fInumber\fP] +[\-\-sources \fInumber\fP] +[\-\-searchers \fInumber\fP] +[\-\-fps] .SH DESCRIPTION The program demonstrates a search algorithm designed for locating a source of odor in turbulent atmosphere. The odor is convected by wind @@ -30,29 +31,32 @@ particles released by them as well as trajectories of searchers who are trying to capture the sources. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 20000 (0.02 seconds.). .TP 8 -.B \-distance \fInumber\fP +.B \-\-distance \fInumber\fP Max initial distance to the source . 10 - 250. Default: 40. .TP 8 -.B \-sources \fInumber\fP +.B \-\-sources \fInumber\fP Max number of sources. Default: 25. .TP 8 -.B \-searchers \fInumber\fP +.B \-\-searchers \fInumber\fP Max number of searchers. Default: 25. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -63,6 +67,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/ant.man b/hacks/ant.man index aa006b6a..05a4ae64 100644 --- a/hacks/ant.man +++ b/hacks/ant.man @@ -3,29 +3,30 @@ ant \- cellular automaton. .SH SYNOPSIS .B ant -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-install] -[\-noinstall] -[\-root] -[\-eyes] -[\-no-eyes] -[\-truchet] -[\-no-truchet] -[\-sharpturn] -[\-no-sharpturn] -[\-delay \fInumber\fP] -[\-cycles \fInumber\fP] -[\-count \fInumber\fP] -[\-size \fInumber\fP] -[\-neighbors 3] -[\-neighbors 4] -[\-neighbors 6] -[\-neighbors 9] -[\-neighbors 12] -[\-ncolors \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-install] +[\-\-noinstall] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-eyes] +[\-\-no-eyes] +[\-\-truchet] +[\-\-no-truchet] +[\-\-sharpturn] +[\-\-no-sharpturn] +[\-\-delay \fInumber\fP] +[\-\-cycles \fInumber\fP] +[\-\-count \fInumber\fP] +[\-\-size \fInumber\fP] +[\-\-neighbors 3] +[\-\-neighbors 4] +[\-\-neighbors 6] +[\-\-neighbors 9] +[\-\-neighbors 12] +[\-\-ncolors \fInumber\fP] +[\-\-fps] .SH DESCRIPTION A cellular automaton that is really a two-dimensional Turing machine: as the heads ("ants") walk along the screen, they change pixel values in @@ -33,44 +34,47 @@ their path. Then, as they pass over changed pixels, their behavior is influenced. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-sharpturns | \-no-sharpturns +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-sharpturns | \-\-no-sharpturns Whether to do sharp turns. .TP 8 -.B \-truchet | \-no-truchet +.B \-\-truchet | \-\-no-truchet Whether to use truchet lines. .TP 8 -.B \-eyes | \-no-eyes +.B \-\-eyes | \-\-no-eyes Whether to draw eyes on the ants. .TP 8 -.B \-delay \fInumber\fP +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 1000 (0.0001 seconds.). .TP 8 -.B \-cycles \fInumber\fP +.B \-\-cycles \fInumber\fP How long to wait until resetting. 0 - 800000. Default: 40000. .TP 8 -.B \-count \fInumber\fP +.B \-\-count \fInumber\fP Ants Count. -20 - 20. Default: -3. .TP 8 -.B \-size \fInumber\fP +.B \-\-size \fInumber\fP Ant Size. -18 - 18. Default: -12. .TP 8 -.B \-neighbors \fIN\fP +.B \-\-neighbors \fIN\fP How many neighbors each cell has. Legal values are 3, 4, 6, 9, and 12. .TP 8 -.B \-ncolors \fInumber\fP +.B \-\-ncolors \fInumber\fP Number of colors. Default: 64. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -81,6 +85,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/apollonian.man b/hacks/apollonian.man index 3dd3ad1d..64497db2 100644 --- a/hacks/apollonian.man +++ b/hacks/apollonian.man @@ -3,47 +3,51 @@ apollonian \- Descartes Circle Theorem. .SH SYNOPSIS .B apollonian -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-no-label] -[\-no-altgeom] -[\-cycles \fInumber\fP] -[\-ncolors \fInumber\fP] -[\-delay \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-no-label] +[\-\-no-altgeom] +[\-\-cycles \fInumber\fP] +[\-\-ncolors \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-fps] .SH DESCRIPTION Packs a large circle with smaller circles, demonstrating the Descartes Circle Theorem. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-label | \-no-label +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-label | \-\-no-label Draw Labels. Boolean. .TP 8 -.B \-altgeom | \-no-altgeom +.B \-\-altgeom | \-\-no-altgeom Include Alternate Geometries. Boolean. .TP 8 -.B \-cycles \fInumber\fP +.B \-\-cycles \fInumber\fP Depth. 1 - 20. Default: 20. .TP 8 -.B \-ncolors \fInumber\fP +.B \-\-ncolors \fInumber\fP Number of Colors. Default: 64. .TP 8 -.B \-delay \fInumber\fP +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 1000000 (1.00 seconds.). .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -54,6 +58,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/apple2.man b/hacks/apple2.man index ec0bcd30..f764bf15 100644 --- a/hacks/apple2.man +++ b/hacks/apple2.man @@ -3,13 +3,14 @@ apple2 \- Apple ][ display emulator .SH SYNOPSIS .B apple2 -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] -[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] -[\-visual \fIvisual\fP] -[\-program \fIcommand to run\fP] -[\-basic] [\-slideshow] [\-text] -[\-meta] [\-esc] [\-bs] [\-del] [\-fast] -[\-fps] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] +[\-\-visual \fIvisual\fP] +[\-\-program \fIcommand to run\fP] +[\-\-basic] [\-\-slideshow] [\-\-text] +[\-\-meta] [\-\-esc] [\-\-bs] [\-\-del] [\-\-fast] +[\-\-fps] .SH DESCRIPTION The .I apple2 @@ -18,8 +19,8 @@ glory. It also reproduces the appearance of display on a color television set of the period. .PP There are 3 modes: basic, slideshow, and text. Normally it chooses a -mode randomly, but you can override with the \fI\-basic\fP, -\fI\-slideshow\fP, or \fI\-text\fP options. +mode randomly, but you can override with the \fI\-\-basic\fP, +\fI\-\-slideshow\fP, or \fI\-\-text\fP options. In basic mode a simulated user types in a Basic program and runs it. @@ -31,7 +32,7 @@ colors, you can only make out the general shape of the pictures. In text mode it displays the output of a command or the contents of a file or URL (via the default .BR xscreensaver\-text (MANSUFFIX) -program, which can be overridden with \fI\-program\fP). +program, which can be overridden with \fI\-\-program\fP). In text mode, it is also a fully functional (if anachronistic) vt100 terminal emulator. @@ -39,32 +40,35 @@ vt100 terminal emulator. .I apple2 accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-basic +.B \-\-basic Choose basic mode .TP 8 -.B \-slideshow +.B \-\-slideshow Choose slideshow mode .TP 8 -.B \-text +.B \-\-text Choose text mode .TP 8 -.B \-program \fIsh-command\fP +.B \-\-program \fIsh-command\fP In text mode, the command to run to generate the text to display. This option may be any string acceptable to /bin/sh. The program will be run at the end of a pipe, and any characters that it prints to @@ -100,37 +104,37 @@ terminal emulators: .sp .fi .TP 8 -.B \-pty -In \fI\-text\fP mode, launch the sub-program under a pty so that it +.B \-\-pty +In \fI\-\-text\fP mode, launch the sub-program under a pty so that it can address the screen directly. This is the default. .TP 8 -.B \-pipe -In \fI\-text\fP mode, launch the sub-program at the end of a pipe: +.B \-\-pipe +In \fI\-\-text\fP mode, launch the sub-program at the end of a pipe: do not let it address the screen directly. .TP 8 -.B \-esc +.B \-\-esc When the user types a key with the Alt or Meta keys held down, send an ESC character first. This is the default. .TP 8 -.B \-meta +.B \-\-meta When Meta or Alt are held down, set the high bit on the character instead. .TP 8 -.B \-del +.B \-\-del Swap Backspace and Delete. This is the default. .TP 8 -.B \-bs +.B \-\-bs Do not swap Backspace and Delete. .TP 8 -.B \-fast +.B \-\-fast Normally, characters are printed at the speed of an original Apple][ computer; however, when using this program as a terminal emulator, the novelty of those 300 baud characters might wear off. You can use -the \fI\-fast\fP option to speed things up a bit. +the \fI\-\-fast\fP option to speed things up a bit. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH TERMINAL EMULATION -By default, \fIapple2\fP allocates a pseudo-tty for the \fI\-text\fP-mode +By default, \fIapple2\fP allocates a pseudo-tty for the \fI\-\-text\fP-mode sub-process to run under. This has the desirable side effect that the program will be able to use .BR ioctl (2) @@ -142,7 +146,7 @@ variable \fITERM\fP to \fIvt100\fP in the child process. Any characters typed on the apple2 window will be passed along to the sub-process. (Note that this only works when running in "window" -mode, not when running in \fI\-root\fP mode under xscreensaver.) +mode, not when running in \fI\-\-root\fP mode under xscreensaver.) .SH ENVIRONMENT .PP .TP 8 @@ -153,6 +157,9 @@ to get the default host and display number. to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. .TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. +.TP 8 .B TERM to inform the sub-process of the type of terminal emulation. .SH X RESOURCES diff --git a/hacks/attraction.man b/hacks/attraction.man index 1238f92a..c7d9d217 100644 --- a/hacks/attraction.man +++ b/hacks/attraction.man @@ -3,17 +3,18 @@ attraction \- interactions of opposing forces .SH SYNOPSIS .B attraction -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] -[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] -[\-visual \fIvisual\fP] [\-points \fIint\fP] [\-threshold \fIint\fP] -[\-mode balls | lines | polygons | splines | filled-splines | tails ] -[\-size \fIint\fP] [\-segments \fIint\fP] [\-delay \fIusecs\fP] -[\-color-shift \fIint\fP] [\-radius \fIint\fP] -[\-vx \fIint\fP] [\-vy \fIint\fP] [\-glow] [\-noglow] -[\-orbit] [\-viscosity \fIfloat\fP] -[\-walls] [\-nowalls] [\-maxspeed] [\-nomaxspeed] -[\-correct-bounce] [\-fast-bounce] -[\-fps] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] +[\-\-visual \fIvisual\fP] [\-\-points \fIint\fP] [\-\-threshold \fIint\fP] +[\-\-mode balls | lines | polygons | splines | filled-splines | tails ] +[\-\-size \fIint\fP] [\-\-segments \fIint\fP] [\-\-delay \fIusecs\fP] +[\-\-color-shift \fIint\fP] [\-\-radius \fIint\fP] +[\-\-vx \fIint\fP] [\-\-vy \fIint\fP] [\-\-glow] [\-\-noglow] +[\-\-orbit] [\-\-viscosity \fIfloat\fP] +[\-\-walls] [\-\-nowalls] [\-\-maxspeed] [\-\-nomaxspeed] +[\-\-correct-bounce] [\-\-fast-bounce] +[\-\-fps] .SH DESCRIPTION The \fIattraction\fP program has several visually different modes of operation, all of which are based on the interactions of a set of control @@ -24,31 +25,34 @@ distance between any two particles. .I attraction accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-points integer +.B \-\-points integer How many control points should be used, or 0 to select the number randomly. Default 0. Between 3 and 15 works best. .TP 8 -.B \-threshold integer +.B \-\-threshold integer The distance (in pixels) from each particle at which the attractive force becomes repulsive. Default 100. .TP 8 -.B \-mode "balls | lines | polygons | tails | splines | filled-splines" +.B \-\-mode "balls | lines | polygons | tails | splines | filled-splines" In \fIballs\fP mode (the default) the control points are drawn as filled circles. The larger the circle, the more massive the particle. @@ -68,34 +72,34 @@ In \fItails\fP mode, the path which each particle follows is indicated by a worm-like trail, whose length is controlled by the \fIsegments\fP parameter. .TP 8 -.B \-size integer +.B \-\-size integer The size of the balls in pixels, or 0, meaning to select the sizes randomly (the default.) If this is specified, then all balls will be the same size. This option has an effect in all modes, since the ``size'' of the balls controls their mass. .TP 8 -.B \-segments integer +.B \-\-segments integer If in \fIlines\fP or \fIpolygons\fP mode, how many sets of line segments or polygons should be drawn. Default 500. This has no effect in \fIballs\fP mode. If \fIsegments\fP is 0, then no segments will ever be erased (this is only useful in color.) .TP 8 -.B \-delay microseconds +.B \-\-delay microseconds How much of a delay should be introduced between steps of the animation. Default 10000, or about 0.01 seconds. .TP 8 -.B \-color-shift int +.B \-\-color-shift int If on a color display, the color of the line segments or polygons will cycle through the color map. This specifies how many lines will be drawn before a new color is chosen. (When a small number of colors are available, increasing this value will yield smoother transitions.) Default 3. This has no effect in \fIballs\fP mode. .TP 8 -.B \-radius +.B \-\-radius The size in pixels of the circle on which the points are initially positioned. The default is slightly smaller than the size of the window. .TP 8 -.B \-glow +.B \-\-glow This is consulted only in \fIballs\fP mode. If this is specified, then the saturation of the colors of the points will vary according to their current acceleration. This has the effect that the balls flare brighter @@ -105,27 +109,27 @@ In \fIglow\fP mode, all of the balls will be drawn the same (random) color, modulo the saturation shifts. In non-glow mode, the balls will each be drawn in a random color that doesn't change. .TP 8 -.B \-noglow +.B \-\-noglow Don't do ``glowing.'' This is the default. .TP 8 -.B \-vx pixels +.B \-\-vx pixels .TP 8 -.B \-vy pixels -Initial velocity of the balls. This has no effect in \fB\-orbit\fP mode. +.B \-\-vy pixels +Initial velocity of the balls. This has no effect in \fB\-\-orbit\fP mode. .TP 8 -.B \-orbit +.B \-\-orbit Make the initial force on each ball be tangential to the circle on which they are initially placed, with the right velocity to hold them in orbit about each other. After a while, roundoff errors will cause the orbit to decay. .TP 8 -.B \-vmult float +.B \-\-vmult float In orbit mode, the initial velocity of the balls is multiplied by this; a number less than 1 will make the balls pull closer together, and a larger number will make them move apart. The default is 0.9, meaning a slight inward pull. .TP 8 -.B \-viscosity float +.B \-\-viscosity float This sets the viscosity of the hypothetical fluid through which the control points move; the default is 1, meaning no resistance. Values higher than 1 aren't interesting; lower values cause less motion. @@ -140,42 +144,42 @@ One interesting thing to try is Give it a few seconds to settle down into a stable clump, and then move the drag the mouse through it to make "waves". .TP 8 -.B \-nowalls +.B \-\-nowalls This will cause the balls to continue on past the edge of the screen or window. They will still be kept track of and can come back. .TP 8 -.B \-walls +.B \-\-walls This will cause the balls to bounce when they get to the edge of the screen or window. This is the default behavior. .TP 8 -.B \-maxspeed +.B \-\-maxspeed Imposes a maximum speed (default). If a ball ends up going faster than this, it will be treated as though there were .9 viscosity until it is under the limit. This stops the balls from continually accelerating (which they have a tendency to do), but also causes balls moving very fast to tend to clump in the lower right corner. .TP 8 -.B \-nomaxspeed +.B \-\-nomaxspeed If this is specified, no maximum speed is set for the balls. .TP 8 -.B \-fast-bounce +.B \-\-fast-bounce Uses the old, simple bouncing algorithm (default). This simply moves any ball that is out of bounds back to a wall and reverses its velocity. This works fine for most cases, but under some circumstances, the simplification can lead to annoying effects. .TP 8 -.B \-correct-bounce +.B \-\-correct-bounce Uses a more intelligent bouncing algorithm. This method actually reflects the balls off the walls until they are within bounds. This can be slow if balls are bouncing a whole lot, perhaps because of -nomaxspeed. .TP 8 -.B \-graphmode none | x | y | both | speed +.B \-\-graphmode none | x | y | both | speed For "x", "y", and "both", displays the given velocities of each ball as a bar graph in the same window as the balls. For "speed", displays the total speed of each ball. Default is "none". .BR .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .B DISPLAY @@ -184,6 +188,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/barcode.man b/hacks/barcode.man index b21fb8fc..d1ef5d83 100644 --- a/hacks/barcode.man +++ b/hacks/barcode.man @@ -3,39 +3,43 @@ barcode \- draws a random sequence of barcodes for the products you enjoy .SH SYNOPSIS .B barcode -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-clock] -[\-clock24] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-clock] +[\-\-clock24] +[\-\-fps] .SH DESCRIPTION This draws a random sequence of colorful barcodes scrolling across your screen. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 10000 (0.02 seconds.). .TP 8 -.B \-clock +.B \-\-clock Instead of drawing a stream of barcodes, draw a barcode-based digital clock. .TP 8 -.B \-clock24 -Same as \fI\-clock\fP, but display 24-hour time instead of 12-hour time. +.B \-\-clock24 +Same as \fI\-\-clock\fP, but display 24-hour time instead of 12-hour time. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -46,6 +50,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/binaryhorizon.man b/hacks/binaryhorizon.man index 926bcbe9..b909925d 100644 --- a/hacks/binaryhorizon.man +++ b/hacks/binaryhorizon.man @@ -3,21 +3,22 @@ binaryhorizon - A system of path tracing particles evolves continuously. .SH SYNOPSIS .B binaryhorizon -[\-fps] -[\-install] -[\-noinstall] -[\-mono] -[\-root] -[\-visual \fIvisual\fP] -[\-window] -[\-window\-id \fIwindow\-id\fP] -[\-color] -[\-no\-color] -[\-growth\-delay \fIdelayms\fP] -[\-particle\-number \fIparticles\fP] -[\-duration \fIsecs\fP] -[\-bicolor] -[\-monocolor] +[\-\-fps] +[\-\-install] +[\-\-noinstall] +[\-\-mono] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-window\-id \fIwindow\-id\fP] +[\-\-color] +[\-\-no\-color] +[\-\-growth\-delay \fIdelayms\fP] +[\-\-particle\-number \fIparticles\fP] +[\-\-duration \fIsecs\fP] +[\-\-bicolor] +[\-\-monocolor] .SH DESCRIPTION A system of path tracing particles evolves continuously from an initial horizon, alternating between colors. @@ -25,58 +26,61 @@ initial horizon, alternating between colors. .I binaryhorizon accepts the following options: .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-mono +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-noinstall +.B \-\-noinstall Don't install a private colormap for the window. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-window\-id \fIwindow\-id\fP +.B \-\-window\-id \fIwindow\-id\fP Specify which window id to use. .TP 8 -.B \-color (Default) +.B \-\-color (Default) Particles have random generated colors that gradually change over time. .TP 8 -.B \-no\-color +.B \-\-no\-color Use the original black and white visualization. .TP 8 -.B \-bicolor (Default) +.B \-\-bicolor (Default) Particles have 2 random colors, starting as white and black. .TP 8 -.B \-monocolor +.B \-\-monocolor Particles have 2 colors, one starting as white and gradually changing, and one staying black. .TP 8 -.B \-fade (Default) +.B \-\-fade (Default) Particles gradually fade between colors over time. .TP 8 -.B \-no-fade +.B \-\-no-fade Every particle is a random color. .TP 8 -.B \-growth\-delay \fIdelayms\fP (Default: \fI10000\fP) +.B \-\-growth\-delay \fIdelayms\fP (Default: \fI10000\fP) Delay in ms between growth cycles. More delay, slower (but less CPU intensive). .TP 8 -.B \-particles\-number \fIparticles\fP (Default: \fI5000\fP) +.B \-\-particles\-number \fIparticles\fP (Default: \fI5000\fP) The number of particles in the system. With more particles the fps can also be affected. .TP 8 -.B \-duration \fIsecs\fP (Default: \fI30\fP) +.B \-\-duration \fIsecs\fP (Default: \fI30\fP) How long between full resets. .SH ENVIRONMENT .PP @@ -87,6 +91,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/binaryring.man b/hacks/binaryring.man index 6d72b3b3..28c0b1e7 100644 --- a/hacks/binaryring.man +++ b/hacks/binaryring.man @@ -3,19 +3,20 @@ binaryring \- A system of path tracing particles evolves continuously from an initial creation. .SH SYNOPSIS .B binaryring -[\-fps] -[\-install] -[\-noinstall] -[\-mono] -[\-root] -[\-visual \fIvisual\fP] -[\-window] -[\-window\-id \fIwindow\-id\fP] -[\-color] -[\-no\-color] -[\-growth\-delay \fIdelayms\fP] -[\-particle\-number \fIparticles\fP] -[\-ring\-radius \fIradius\fP] +[\-\-fps] +[\-\-install] +[\-\-noinstall] +[\-\-mono] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-window\-id \fIwindow\-id\fP] +[\-\-color] +[\-\-no\-color] +[\-\-growth\-delay \fIdelayms\fP] +[\-\-particle\-number \fIparticles\fP] +[\-\-ring\-radius \fIradius\fP] .SH DESCRIPTION A system of path tracing particles evolves continuously from an initial circular creation. Ages of darkness play arbitrarily with @@ -24,45 +25,48 @@ ages of light. .I binaryring accepts the following options: .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-mono +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-noinstall +.B \-\-noinstall Don't install a private colormap for the window. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-window\-id \fIwindow\-id\fP +.B \-\-window\-id \fIwindow\-id\fP Specify which window id to use. .TP 8 -.B \-color (Default) +.B \-\-color (Default) Particles have random generated colors that gradually change over time. .TP 8 -.B \-no\-color +.B \-\-no\-color Use the original black and white visualization. .TP 8 -.B \-growth\-delay \fIdelayms\fP (Default: \fI10000\fP) +.B \-\-growth\-delay \fIdelayms\fP (Default: \fI10000\fP) Delay in ms between growth cycles. More delay, slower (but less CPU intensive). .TP 8 -.B \-particles\-number \fIparticles\fP (Default: \fI5000\fP) +.B \-\-particles\-number \fIparticles\fP (Default: \fI5000\fP) The number of particles in the system. With more particles the fps can also be affected. .TP 8 -.B \-ring\-radius \fIradius\fP (Default: \fI40\fP) +.B \-\-ring\-radius \fIradius\fP (Default: \fI40\fP) The radius of the ring where the particles are born, in pixels. .SH ENVIRONMENT .PP @@ -73,6 +77,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/blaster.man b/hacks/blaster.man index 92f26fd2..fc0ff22f 100644 --- a/hacks/blaster.man +++ b/hacks/blaster.man @@ -3,43 +3,47 @@ blaster \- simulation of space combat .SH SYNOPSIS .B blaster -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-num_robots \fInumber\fP] -[\-num_lasers \fInumber\fP] -[\-num_stars \fInumber\fP] -[\-delay \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-num_robots \fInumber\fP] +[\-\-num_lasers \fInumber\fP] +[\-\-num_stars \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-fps] .SH DESCRIPTION Draws a simulation of flying space-combat robots (cleverly disguised as colored circles) doing battle in front of a moving star field. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-num_robots \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-num_robots \fInumber\fP Robots. 2 - 50. Default: 5. .TP 8 -.B \-num_lasers \fInumber\fP +.B \-\-num_lasers \fInumber\fP Lasers. 1 - 100. Default: 3. .TP 8 -.B \-num_stars \fInumber\fP +.B \-\-num_stars \fInumber\fP Stars. 5 - 200. Default: 50. .TP 8 -.B \-delay \fInumber\fP +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 10000 (0.01 seconds.). .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -50,6 +54,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/blitspin.man b/hacks/blitspin.man index 1b70c7bf..8a4ef0d0 100644 --- a/hacks/blitspin.man +++ b/hacks/blitspin.man @@ -3,10 +3,12 @@ blitspin \- rotate a bitmap in an interesting way .SH SYNOPSIS .B blitspin -[\-display \fIhost:display.screen\fP] -[\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] -[\-mono] [\-install] [\-visual \fIvisual\fP] [\-bitmap \fIfilename\fP] -[\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP] [\-duration \fIsecs\fP] +[\-\-display \fIhost:display.screen\fP] +[\-\-foreground \fIcolor\fP] [\-\-background \fIcolor\fP] [\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-mono] [\-\-install] [\-\-visual \fIvisual\fP] [\-\-bitmap \fIfilename\fP] +[\-\-delay \fIusecs\fP] [\-\-delay2 \fIusecs\fP] [\-\-duration \fIsecs\fP] .SH DESCRIPTION The \fIblitspin\fP program repeatedly rotates a bitmap by 90 degrees by using logical operations: the bitmap is divided into quadrants, and the @@ -19,23 +21,26 @@ and the size must be a power of 2. .I blitspin accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-bitmap \fIfilename\fP +.B \-\-bitmap \fIfilename\fP The file name of a bitmap to rotate. It need not be square: it will be padded with the background color. If unspecified or the string \fI(default)\fP, a builtin bitmap is used. @@ -47,7 +52,7 @@ thus may be a color image. The \fB*bitmapFilePath\fP resource will be searched if the bitmap name is not a fully-qualified pathname. .TP 8 -.B \-grab\-screen +.B \-\-grab\-screen If this option is specified, then the image which is spun will be grabbed from the portion of the screen underlying the blitspin window, or from the system's video input, or from a random file on disk, as indicated by @@ -57,25 +62,28 @@ see .BR xscreensaver\-settings (1) for more details. .TP 8 -.B \-delay \fImicroseconds\fP +.B \-\-delay \fImicroseconds\fP How long to delay between steps of the rotation process, in microseconds. Default is 500000, one-half second. .TP 8 -.B \-duration \fIseconds\fP +.B \-\-duration \fIseconds\fP How long to run before loading a new image. Default 120 seconds. .TP 8 -.B \-delay2 \fImicroseconds\fP +.B \-\-delay2 \fImicroseconds\fP How long to delay between each 90-degree rotation, in microseconds. Default is 500000, one-half second. .B DISPLAY to get the default host and display number. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/bouboule.man b/hacks/bouboule.man index cc50c28b..e9e4e22e 100644 --- a/hacks/bouboule.man +++ b/hacks/bouboule.man @@ -3,47 +3,52 @@ bouboule \- draws spinning 3D blobs .SH SYNOPSIS .B bouboule -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-delay \fImicroseconds\fP] [\-cycles \fIinteger\fP] [\-count \fIinteger\fP] [\-3d] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] [\-\-visual \fIvisual\fP] [\-\-ncolors \fIinteger\fP] [\-\-delay \fImicroseconds\fP] [\-\-cycles \fIinteger\fP] [\-\-count \fIinteger\fP] [\-3d] -[\-fps] +[\-\-fps] .SH DESCRIPTION The \fIbouboule\fP program draws spinning 3D blobs. .SH OPTIONS .I bouboule accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-ncolors \fIinteger\fP +.B \-\-ncolors \fIinteger\fP How many colors should be used (if possible). Default 64. The colors used cycle through the hue, making N stops around the color wheel. .TP 8 -.B \-cycles \fIinteger\fP +.B \-\-cycles \fIinteger\fP .TP 8 -.B \-count \fIinteger\fP +.B \-\-count \fIinteger\fP .TP 8 .B \-3d Do red/blue 3d separations (for 3d glasses.) .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -54,6 +59,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/boxfit.man b/hacks/boxfit.man index 8e14dba5..dc49a8ee 100644 --- a/hacks/boxfit.man +++ b/hacks/boxfit.man @@ -3,19 +3,20 @@ boxfit \- fills space with a gradient of growing boxes or circles. .SH SYNOPSIS .B boxfit -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fIusecs\fP] -[\-count \fIint\fP] -[\-growby \fIint\fP] -[\-spacing \fIint\fP] -[\-border \fIint\fP] -[\-circles | \-squares | \-random] -[\-grab] -[\-peek] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fIusecs\fP] +[\-\-count \fIint\fP] +[\-\-growby \fIint\fP] +[\-\-spacing \fIint\fP] +[\-\-border \fIint\fP] +[\-\-circles | \-\-squares | \-\-random] +[\-\-grab] +[\-\-peek] +[\-\-fps] .SH DESCRIPTION Packs the screen with growing boxes or circles, colored according to a horizontal or vertical gradient. The objects grow until they touch, @@ -23,39 +24,42 @@ then stop. When the screen is full, they shrink away and the process restarts. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fImicroseconds\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fImicroseconds\fP How much of a delay should be introduced between steps of the animation. Default 20000, or about 0.02 seconds. .TP 8 -.B \-count \fIint\fP +.B \-\-count \fIint\fP How many boxes or circles to animate simultaneously; default 50. Smaller numbers yield larger boxes/circles. .TP 8 -.B \-growby \fIint\fP +.B \-\-growby \fIint\fP How many pixels the objects should grow by, each frame. Default 1. .TP 8 -.B \-spacing \fIint\fP +.B \-\-spacing \fIint\fP How many pixels of space should be left between the objects. Default 1. .TP 8 -.B \-border \fIint\fP +.B \-\-border \fIint\fP Thickness of the colored border around each object. Default 1. .TP 8 -.B \-circles\fB | \-squares\fP | \-random\fP +.B \-\-circles\fB | \-\-squares\fP | \-\-random\fP Draw circles, squares, or choose randomly (the default). .TP 8 -.B \-grab +.B \-\-grab Normally it colors the boxes with a horizontal or vertical gradient. -If \fI\-grab\fP is specified, it will instead load a random image, +If \fI\-\-grab\fP is specified, it will instead load a random image, and color the boxes according to the colors in that image. As the picture fills in, some features of the underlying image may become recognisable. @@ -69,12 +73,12 @@ file; see .BR xscreensaver\-settings (1) for more details. .TP 8 -.B \-peek +.B \-\-peek This option says to briefly show you the underlying image before beginning. The default is not to show the unadulterated image at all. -(This only has an effect when \fI\-grab\fP is used.) +(This only has an effect when \fI\-\-grab\fP is used.) .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -85,6 +89,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/braid.man b/hacks/braid.man index 19a32820..ec6cfb52 100644 --- a/hacks/braid.man +++ b/hacks/braid.man @@ -3,43 +3,48 @@ braid \- draws random color-cycling braids around a circle .SH SYNOPSIS .B braid -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-delay \fImicroseconds\fP] [\-cycles \fIinteger\fP] [\-count \fIinteger\fP] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] [\-\-visual \fIvisual\fP] [\-\-ncolors \fIinteger\fP] [\-\-delay \fImicroseconds\fP] [\-\-cycles \fIinteger\fP] [\-\-count \fIinteger\fP] -[\-fps] +[\-\-fps] .SH DESCRIPTION The \fIbraid\fP program draws random color-cycling braids around a circle. .SH OPTIONS .I braid accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-ncolors \fIinteger\fP +.B \-\-ncolors \fIinteger\fP How many colors should be used (if possible). Default 64. The colors used cycle through the hue, making N stops around the color wheel. .TP 8 -.B \-cycles \fIinteger\fP +.B \-\-cycles \fIinteger\fP .TP 8 -.B \-count \fIinteger\fP +.B \-\-count \fIinteger\fP .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -50,6 +55,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/bsod.c b/hacks/bsod.c index e9d55b69..85203fa5 100644 --- a/hacks/bsod.c +++ b/hacks/bsod.c @@ -217,7 +217,7 @@ struct bsod_state { (bst)->pos++; \ } while (0) -/* Set the prevailing top/bottom margins (used when scrolling and cropping text) +/* Set the prevailing top/bottom margins (used when scrolling/cropping text) */ #define BSOD_VERT_MARGINS(bst,top,bottom) do { \ ensure_queue (bst); \ @@ -1254,21 +1254,21 @@ vmware (Display *dpy, Window window) "VMware ESX Server [Releasebuild-98103]\n"); BSOD_COLOR (bst, fg, bg); BSOD_TEXT (bst, LEFT, - "PCPU 1 locked up. Failed to ack TLB invalidate.\n" - "frame=0x3a37d98 ip=0x625e94 cr2=0x0 cr3=0x40c66000 cr4=0x16c\n" - "es=0xffffffff ds=0xffffffff fs=0xffffffff gs=0xffffffff\n" - "eax=0xffffffff ebx=0xffffffff ecx=0xffffffff edx=0xffffffff\n" - "ebp=0x3a37ef4 esi=0xffffffff edi=0xffffffff err=-1 eflags=0xffffffff\n" - "*0:1037/helper1-4 1:1107/vmm0:Fagi 2:1121/vmware-vm 3:1122/mks:Franc\n" - "0x3a37ef4:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x3a37f10, 0x3a37f48\n" - "0x3a37f04:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x1, 0x14a03a0\n" - "0x3a37f48:[0x64bfa4]TLBDoInvalidate+0x38f stack: 0x3a37f54, 0x40, 0x2\n" - "0x3a37f70:[0x66da4d]XMapForceFlush+0x64 stack: 0x0, 0x4d3a, 0x0\n" - "0x3a37fac:[0x652b8b]helpFunc+0x2d2 stack: 0x1, 0x14a4580, 0x0\n" - "0x3a37ffc:[0x750902]CpuSched_StartWorld+0x109 stack: 0x0, 0x0, 0x0\n" - "0x3a38000:[0x0]blk_dev+0xfd76461f stack: 0x0, 0x0, 0x0\n" - "VMK uptime: 7:05:43:45.014 TSC: 1751259712918392\n" - "Starting coredump to disk\n"); + "PCPU 1 locked up. Failed to ack TLB invalidate.\n" + "frame=0x3a37d98 ip=0x625e94 cr2=0x0 cr3=0x40c66000 cr4=0x16c\n" + "es=0xffffffff ds=0xffffffff fs=0xffffffff gs=0xffffffff\n" + "eax=0xffffffff ebx=0xffffffff ecx=0xffffffff edx=0xffffffff\n" + "ebp=0x3a37ef4 esi=0xffffffff edi=0xffffffff err=-1 eflags=0xffffffff\n" + "*0:1037/helper1-4 1:1107/vmm0:Fagi 2:1121/vmware-vm 3:1122/mks:Franc\n" + "0x3a37ef4:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x3a37f10, 0x3a37f48\n" + "0x3a37f04:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x1, 0x14a03a0\n" + "0x3a37f48:[0x64bfa4]TLBDoInvalidate+0x38f stack: 0x3a37f54, 0x40, 0x2\n" + "0x3a37f70:[0x66da4d]XMapForceFlush+0x64 stack: 0x0, 0x4d3a, 0x0\n" + "0x3a37fac:[0x652b8b]helpFunc+0x2d2 stack: 0x1, 0x14a4580, 0x0\n" + "0x3a37ffc:[0x750902]CpuSched_StartWorld+0x109 stack: 0x0, 0x0, 0x0\n" + "0x3a38000:[0x0]blk_dev+0xfd76461f stack: 0x0, 0x0, 0x0\n" + "VMK uptime: 7:05:43:45.014 TSC: 1751259712918392\n" + "Starting coredump to disk\n"); BSOD_CHAR_DELAY (bst, 10000); BSOD_TEXT (bst, LEFT, "using slot 1 of 1... "); BSOD_CHAR_DELAY (bst, 300000); @@ -1284,7 +1284,8 @@ vmware (Display *dpy, Window window) BSOD_CHAR_DELAY (bst, 10000); BSOD_TEXT (bst, LEFT, "Press Escape to enter local debugger\n"); BSOD_CHAR_DELAY (bst, 10000); - BSOD_TEXT (bst, LEFT, "Remote debugger activated. Local debugger no longer available.\n"); + BSOD_TEXT (bst, LEFT, + "Remote debugger activated. Local debugger no longer available.\n"); /* BSOD_CURSOR (bst, CURSOR_LINE, 240000, 999999);*/ @@ -1296,6 +1297,217 @@ vmware (Display *dpy, Window window) return bst; } +/* VMware ESXi 7.0 on a 64-bit Arm host (actually ESXi-Arm Fling) + by Andrei E. Warkentin . + */ +static struct bsod_state * +vmware_arm (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, + "vmware-arm", "VMwareArm"); + + unsigned i = 2; + unsigned msg_row; + unsigned long fg = bst->fg; + char t_string[25]; + time_t t_now = time(NULL); + unsigned long font_height = bst->font->ascent + bst->font->descent; + + unsigned long psod_bg = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-psod.background", + "vmware-arm-psod.background"); + unsigned long term_bg = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-term.background", + "vmware-arm-term.background"); + unsigned long term_fg2 = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-term.foreground2", + "vmware-arm-term.foreground2"); + unsigned long term_fg3 = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-term.foreground3", + "vmware-arm-term.foreground3"); + unsigned long dbg_bg = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-dbg.background", + "vmware-arm-dbg.background"); + unsigned long dbg_fg = get_pixel_resource(dpy, bst->xgwa.colormap, + "vmware-arm-dbg.foreground", + "vmware-arm-dbg.foreground"); + unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "vmware-arm.foreground2", + "vmware-arm.foreground2"); + + BSOD_WRAP (bst); + BSOD_MARGINS(bst, 0, 0); + BSOD_VERT_MARGINS(bst, 0, 0); + + /* + * statusterm. + */ + BSOD_TRUNCATE(bst); + BSOD_COLOR (bst, term_bg, fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_MOVETO(bst, 0, font_height * 6); + BSOD_COLOR (bst, fg, term_bg); + BSOD_TEXT (bst, LEFT, + " VMware ESXi 7.0.0 (VMKernel Release Build 19076756)"); + BSOD_MOVETO(bst, 0, font_height * 8); + BSOD_COLOR (bst, fg, term_bg); + BSOD_TEXT (bst, LEFT, " PINE64 Quartz64 Model A"); + BSOD_MOVETO(bst, 0, font_height * 10); + BSOD_COLOR (bst, term_fg2, term_bg); + BSOD_TEXT (bst, LEFT, " ARM Limited Cortex-A55 r2p0"); + BSOD_MOVETO(bst, 0, font_height * 11); + BSOD_COLOR (bst, term_fg2, term_bg); + BSOD_TEXT (bst, LEFT, " 7.7 GiB Memory"); + + msg_row = 1 + (bst->xgwa.height / (font_height * 2)); + if (msg_row > 11) { + BSOD_WRAP(bst); + BSOD_MOVETO(bst, 0, font_height * msg_row); + BSOD_COLOR (bst, term_fg3, term_bg); + strftime(t_string, sizeof(t_string), "%Y-%m-%dT%H:%M:%S.000Z", + localtime(&t_now)); + BSOD_TEXT (bst, LEFT, t_string); + BSOD_TEXT (bst, LEFT, + " cpu0:65802)Failed to verify signatures of the following vib(s):" + " [bnxtnet bnxtroce brcmfcoe brcmnvmefc elx-esx-libelxima.so" + " eslxiscsi elxnet ena esx base esx-dvfilter-generic-fastpath" + " esx-ui esx-update i40en i40iwn iavmd igbn iser$"); + } + + BSOD_PAUSE (bst, 10000000); + + /* + * Now the PSOD. + */ + BSOD_TRUNCATE(bst); + BSOD_COLOR (bst, psod_bg, fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_MOVETO(bst, 0, bst->font->ascent); + BSOD_COLOR (bst, fg2, psod_bg); + BSOD_TEXT (bst, LEFT, + "VMware ESX 7.0.0 [Releasebuild-19076756 aarch64]\n"); + BSOD_COLOR (bst, fg, psod_bg); + BSOD_LINE_DELAY (bst, 1000); + BSOD_TEXT (bst, LEFT, + "EXCVEC_CUREL_SP_EL0_SYNCH Exception 0 in world 131126:HELPER_UPLIN" + " (ec 0x25 il 1 iss 0x47 far_el1 0x315d3541b8 far_el2 0x4501843b1000)" + "\nTTB=0x12ade8000" + "\nCurrentEL=2 SP_EL0 DAIF" + "\nSCTLR_EL2=0x30c0180d sa0 SA C a M" + "\n[ 0] 4501843b0000 [ 1] 0 [ 2]" + " 1000 [ 3] 4501843b1000" + "\n[ 4] 451a01b1be20 [ 5] 0 [ 6]" + " 4305be607a5a [ 7] 4200400001c0" + "\n[ 8] 0 [ 9] 451a01b1be20 [10]" + " 1 [11] 1" + "\n[12] ffffed40 [13] 420040000080 [14]" + " 41fffa5d7000 [15] 41fffa5d7c20" + "\n[16] 1 [17] 4 [18]" + " 41fffa5d7c08 [19] 451a01b1be70" + "\n[20] 43024240b680 [21] 4305be601900 [22]" + " 4305be6012c0 [23] 41ffd0c00000" + "\n[24] 4305be601220 [25] bad0001 [26]" + " 0 [27] 43006fc01220" + "\n[28] 4303d5001220 [29] 0 [30] 42003b3ceb6c" + "\n[pc] 42003a344d54 [sp] 451a01b1bdd0 [psr] 20000248" + "\n*PCPU0:131126/HELPER_UPLINK_ASYNC_CALL_QUEUE" + "\nPCPU 0: SUUU" + "\nCode start: 0x42003a200000 VMK uptime: 0:00:05:35.425" + "\n0x451a01b1bdd0:[0x42003a344d54]vmk_Memset@vmkernel#nover+0x28" + " stack: 0x42003b3cfa48" + "\n0x451a01b1bdd0:[0x42003b3ceb68]EQOSEnable@(eqos)#+0xe0" + " stack: 0x42003b3cfa48" + "\n0x451a01b1be20:[0x42003b3c9220]SETHUplAssociate@(eqos)#+0x88" + " stack: 0x43024240b680" + "\n0x451a01b1be80:[0x42003a48a078]UplinkDeviceAssociateAsyncCB" + "@vmkernel#nover+0x50 stack: 0x43024240bb08" + "\n0x451a01b1bed0:[0x42003a555a6c]UplinkAsyncProcessCallsHelperCB" + "@vmkernel#nover+0x12c stack: 0x451a01b21000" + "\n0x451a01b1bf20:[0x42003a2fd510]HelperQueueFunc@vmkernel#nover+0x174" + " stack: 0x451a01b21100" + "\n0x451a01b1bfe0:[0x42003a59e4fc]CpuSched_StartWorld@vmkernel#nover+0x70" + " stack: 0x0" + "\n0x451a01b1c000:[0x42003a5ec610]CpuSched_UseMwaitCallback" + "@vmkernel#nover+0x8 stack: 0x0" + "\nNo place on disk to dump data." + "\nCoredump to file: /vmfs/volumes/3a4fcb25-5f6ca096-c940-70886b86100c" + "/vmkdump/00000000-0000-0000-0000-000000000000.dumpfile." + "\nFaulting world regs (01/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nVmm code/data (02/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nVmk code/rodata/stack (03/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nVmk data/heap (04/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nPCPU (05/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nWorld-specific data (06/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nVASpace (08/15)"); + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, "\nPFrame (09/15)"); + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, "\nMemXferFs (11/15)"); + BSOD_PAUSE (bst, 300000); + BSOD_TEXT (bst, LEFT, "\nDump Files (13/15)"); + BSOD_PAUSE (bst, 600000); + BSOD_TEXT (bst, LEFT, "\nCollecting userworld dumps (14/15)"); + BSOD_PAUSE (bst, 600000); + BSOD_TEXT (bst, LEFT, + "\nFinalized dump header (15/15) FileDump: Successful."); + BSOD_PAUSE (bst, 10000); + BSOD_TEXT (bst, LEFT, + "\nNo port for remote debugger. Press \"Escape\" for local debugger."); + BSOD_PAUSE (bst, 1000000); + + /* + * Local debugger. + */ + BSOD_COLOR (bst, dbg_bg, dbg_fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_MOVETO(bst, 0, bst->font->ascent); + BSOD_TEXT (bst, LEFT, "vmkernel debugger (h for help)"); + BSOD_RECT (bst, True, 0, bst->font->ascent + bst->font->descent / 2, + bst->xgwa.width, bst->font->ascent); + BSOD_COLOR (bst, dbg_fg, dbg_bg); + BSOD_TEXT (bst, LEFT, "\n[PCPU2] VMKDBG> _"); + while (i--) { + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, "\bh_"); + BSOD_PAUSE (bst, 10000); + BSOD_TEXT (bst, LEFT, "\b \nh : help" + "\nreboot : reboot" + "\nlivedump: Create live coredump without crashing system" + "\nl : display vmkernel log" + "\np : display content of symbol" + "\ns : display storage dump+boot info" + "\nx : display 32-bit content of address" + "\nx/N : display N bytes of content at address" + "\ng port : bind remote debugger to port (com1 or com2)" + "\nbt N : show backtrace for CPU N" + "\nq : quit debug terminal" + "\n[PCPU2] VMKDBG> _"); + } + BSOD_PAUSE (bst, 100000); + BSOD_TEXT (bst, LEFT, "\bre_"); + BSOD_PAUSE (bst, 500000); + BSOD_TEXT (bst, LEFT, "\bb_"); + BSOD_PAUSE (bst, 50000); + BSOD_TEXT (bst, LEFT, "\bo_"); + BSOD_PAUSE (bst, 50000); + BSOD_TEXT (bst, LEFT, "\bo_"); + BSOD_PAUSE (bst, 50000); + BSOD_TEXT (bst, LEFT, "\bt_"); + BSOD_PAUSE (bst, 2000000); + BSOD_COLOR (bst, dbg_bg, dbg_fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_PAUSE (bst, 1000000); + + XClearWindow (dpy, window); + return bst; +} + /* Windows NT 3.1 - 4.0 */ @@ -1357,29 +1569,30 @@ windows_nt (Display *dpy, Window window) case 3: BSOD_TEXT (bst, CENTER, - "Microsoft (R) Windows NT (R) Version 5.0 (Build 1796)\n" - "1 System Processor [128 MB Memory] MultiProcessor Kernel\n" - "\n" - "*** STOP: 0x0000006B (0xC000003A, 0x00000002,0x00000000,0x00000000)\n" - "PROCESS1_INITIALIZATION_FAILED\n" - "\n" - "If this is the first time you[ve seen this Stop error screen,\n" - "restart your computer. If this screen appears again, follow\n" - "these steps:\n" - "\n" - "Check to make sure any new hardware or software is properly installed.\n" - "If this is a new installation, ask your hardware or software manufacturer\n" - "for any Windows NT updates you might need.\n" - "\n" - "If problems continue, disable or remove any newly installed hardware\n" - "or software. Disable BIOS memory options such as caching or shadowing.\n" - "If you need to use Safe Mode to remove or disable components, restart\n" - "your computer, press F8 to select Advanced Startup Options, and then\n" - "select Safe Mode.\n" - "\n" - "Refer to your Getting Started manual for more information on\n" - "troubleshooting Stop errors.\n" - "\n"); + "Microsoft (R) Windows NT (R) Version 5.0 (Build 1796)\n" + "1 System Processor [128 MB Memory] MultiProcessor Kernel\n" + "\n" + "*** STOP: 0x0000006B (0xC000003A, 0x00000002,0x00000000,0x00000000)\n" + "PROCESS1_INITIALIZATION_FAILED\n" + "\n" + "If this is the first time you[ve seen this Stop error screen,\n" + "restart your computer. If this screen appears again, follow\n" + "these steps:\n" + "\n" + "Check to make sure any new hardware or software is properly installed.\n" + "If this is a new installation, ask your hardware or software" + " manufacturer\n" + "for any Windows NT updates you might need.\n" + "\n" + "If problems continue, disable or remove any newly installed hardware\n" + "or software. Disable BIOS memory options such as caching or shadowing.\n" + "If you need to use Safe Mode to remove or disable components, restart\n" + "your computer, press F8 to select Advanced Startup Options, and then\n" + "select Safe Mode.\n" + "\n" + "Refer to your Getting Started manual for more information on\n" + "troubleshooting Stop errors.\n" + "\n"); break; default: abort(); @@ -1559,35 +1772,35 @@ windows_xp (Display *dpy, Window window) break; case 5: /* Windows 8 */ BSOD_TEXT (bst, LEFT, - "A problem has been detected and windows has been shut down to prevent\n" - "damage to your computer.\n" - "\n" - "SYSTEM_SERVICE_EXCEPTION\n" - "\n" - "If this is the first time you[ve seen this Stop error screen,\n" - "restart your computer. If this screen appears again, follow\n" - "these steps:\n" - "\n" - "Check to make sure any new hardware or software is properly installed.\n" - "If this is a new installation, ask your hardware or software" - " manufacturer\n" - "for any Windows NT updates you might need.\n" - "\n" - "If problems continue, disable or remove any newly installed hardware\n" - "or software. Disable BIOS memory options such as caching or shadowing.\n" - "If you need to use Safe Mode to remove or disable components, restart\n" - "your computer, press F8 to select Advanced Startup Options, and then\n" - "select Safe Mode.\n" - "\n" - "Technical information:\n" - "\n" - "*** STOP: 0x0000003B (0x00000000c000005,0xFFFFF880041C9062," - "0xFFFFF88002E22F60,0x0000000000000000(\n" - "\n" - "*** dxgmms1.sys - Address FFFFF880041C9062 base at FFFFF8800418F000," - " DateStamp 4cdb7409\n" - "\n" - "Collecting data for crash dump ...\n"); + "A problem has been detected and windows has been shut down to prevent\n" + "damage to your computer.\n" + "\n" + "SYSTEM_SERVICE_EXCEPTION\n" + "\n" + "If this is the first time you[ve seen this Stop error screen,\n" + "restart your computer. If this screen appears again, follow\n" + "these steps:\n" + "\n" + "Check to make sure any new hardware or software is properly installed.\n" + "If this is a new installation, ask your hardware or software" + " manufacturer\n" + "for any Windows NT updates you might need.\n" + "\n" + "If problems continue, disable or remove any newly installed hardware\n" + "or software. Disable BIOS memory options such as caching or shadowing.\n" + "If you need to use Safe Mode to remove or disable components, restart\n" + "your computer, press F8 to select Advanced Startup Options, and then\n" + "select Safe Mode.\n" + "\n" + "Technical information:\n" + "\n" + "*** STOP: 0x0000003B (0x00000000c000005,0xFFFFF880041C9062," + "0xFFFFF88002E22F60,0x0000000000000000(\n" + "\n" + "*** dxgmms1.sys - Address FFFFF880041C9062 base at FFFFF8800418F000," + " DateStamp 4cdb7409\n" + "\n" + "Collecting data for crash dump ...\n"); BSOD_PAUSE (bst, 4000000); BSOD_TEXT (bst, LEFT, "Initializing disk for for crash dump ...\n"); @@ -1999,6 +2212,13 @@ windows_ransomware (Display *dpy, Window window) "Well actually, your screen isn't needed anymore.", "u just got popped with some 0day shit!!", "M'lady,", + "ALL UR APES ARE GONE!!1", + "Oops, all your apes are gone!", + "Oops, all your apes are gone!!", + "Oops, all ur tokens have been funged!", + "Oops, all your turkens have been funged!", + "Oops, all your tokens have been funged!", + "YOUR TOKENS ARE FUNGED. PRAY I DO NOT FUNGE THEM FURTHER.", }; const char *header_quip = header_quips[random() % countof(header_quips)]; @@ -2015,9 +2235,19 @@ windows_ransomware (Display *dpy, Window window) "you are bad and you should feel bad", "you used the wifi at defcon", "you lack official Clown Strike[TM] threaty threat technology", + "Capitalism is a death cult", + "Web3 is in full effect", + "paperclip maximizers gonna paperclip maximize", + "the line is pleased", + "line goes up", + "you didn't HODL", + "you didn't click hard enough and now Tinkerbelle is dead", + "of your tesla stonks", + "MAMMON HUNGERS", }; - const char *excuse_quip = excuse_quips[random() % countof(excuse_quips)]; + const char *excuse_quip = excuse_quips[random() % countof(excuse_quips)]; + const char *excuse_quip_2 = excuse_quips[random() % countof(excuse_quips)]; /* WELL ACTUALLY, screensavers aren't really necessary anymore because... */ const char * const screensaver_quips[] = { @@ -2062,8 +2292,7 @@ windows_ransomware (Display *dpy, Window window) "payment, press . Best time to check: 4-6am, Mon-Fri.\n", "\n", "*Why Did I Get This?\n", - "You got this because ", "[Q]", - ". Also you didn't click hard enough and now Tinkerbelle is dead.\n", + "You got this because ", "[Q]", ". Also ", "[Q2]", ".\n", "\n", "*But Aren't Screensavers Are Necessary?\n", "WELL ACTUALLY, screensavers aren't really necessary anymore because ", @@ -2136,6 +2365,9 @@ windows_ransomware (Display *dpy, Window window) int top_height, bottom_height; int x, y; + while (excuse_quip == excuse_quip_2) + excuse_quip_2 = excuse_quips[random() % countof(excuse_quips)]; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ for (i = 0; i < n; i++) { @@ -2278,7 +2510,8 @@ windows_ransomware (Display *dpy, Window window) { const char *s = lines[i]; if (!strcmp(s, "[C]")) s = currency; - else if (!strcmp(s, "[Q]")) s = excuse_quip; + else if (!strcmp(s, "[Q]")) s = excuse_quip; + else if (!strcmp(s, "[Q2]")) s = excuse_quip_2; else if (!strcmp(s, "[S]")) s = screensaver_quip; if (*s == '*') @@ -2312,7 +2545,8 @@ windows_ransomware (Display *dpy, Window window) x + left_column_width + margin, y + top_height + right_column_height + line_height * 2); - sprintf(buf, "Send $%.2f of %s to this address:\n", 101+frand(888), currency); + sprintf(buf, "Send $%.2f of %s to this address:\n", 101+frand(888), + currency); BSOD_TEXT (bst, LEFT, buf); BSOD_COLOR (bst, fg2, bg2); @@ -6489,6 +6723,7 @@ static const struct { { "GLaDOS", glados }, { "Android", android }, { "VMware", vmware }, + { "VMwareArm", vmware_arm }, { "Encom", encom }, { "DVD", dvd }, { "Tivo", tivo }, @@ -6814,6 +7049,7 @@ static const char *bsod_defaults [] = { "*doGLaDOS: True", "*doAndroid: False", "*doVMware: True", + "*doVMwareArm: True", "*doEncom: True", "*doDVD: True", "*doTivo: True", @@ -6930,6 +7166,16 @@ static const char *bsod_defaults [] = { ".vmware.foreground2: Yellow", ".vmware.background: #a700a8", /* purple */ + ".vmware-arm.foreground: #FFFFFF", + ".vmware-arm.foreground2: #FFFF00", + ".vmware-arm.background: #555555", + ".vmware-arm-psod.background: #a700a8", + ".vmware-arm-dbg.background: #000000", + ".vmware-arm-dbg.foreground: #ABABAB", + ".vmware-arm-term.background: #555555", + ".vmware-arm-term.foreground2: #AAAAAA", + ".vmware-arm-term.foreground3: #FF5757", + ".tivo.background: #339020", ".tivo.foreground: #B8E6BA", @@ -7078,6 +7324,8 @@ static const XrmOptionDescRec bsod_options [] = { { "-no-android", ".doAndroid", XrmoptionNoArg, "False" }, { "-vmware", ".doVMware", XrmoptionNoArg, "True" }, { "-no-vmware", ".doVMware", XrmoptionNoArg, "False" }, + { "-vmware-arm", ".doVMwareArm", XrmoptionNoArg, "True" }, + { "-no-vmware-arm", ".doVMwareArm", XrmoptionNoArg, "False" }, { "-encom", ".doEncom", XrmoptionNoArg, "True" }, { "-no-encom", ".doEncom", XrmoptionNoArg, "False" }, { "-dvd", ".doDVD", XrmoptionNoArg, "True" }, diff --git a/hacks/bsod.man b/hacks/bsod.man index de054fc1..dce09e03 100644 --- a/hacks/bsod.man +++ b/hacks/bsod.man @@ -3,10 +3,11 @@ bsod \- Blue Screen of Death emulator .SH SYNOPSIS .B bsod -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] -[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] -[\-visual \fIvisual\fP] [\-delay \fIseconds\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] +[\-\-visual \fIvisual\fP] [\-\-delay \fIseconds\fP] +[\-\-fps] .SH DESCRIPTION The .I bsod @@ -24,29 +25,32 @@ NCD X Terminals. .I bsod accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-delay \fIdelay\fP +.B \-\-delay \fIdelay\fP The duration each crash-mode is displayed before selecting another. .TP 8 -.B \-only \fIwhich\fP -Tell it to run only one mode, e.g., \fI\-only HPUX\fP. +.B \-\-only \fIwhich\fP +Tell it to run only one mode, e.g., \fI\-\-only HPUX\fP. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -57,6 +61,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH X RESOURCES Notable X resources supported include the following, which control which hacks are displayed and which aren't. @@ -95,7 +102,7 @@ by default, because they're really not all that interesting looking unless you're a fan of those systems. There are command-line options for all of these: -e.g., \fI\-bsd\fP, \fI\-no-bsd\fP. (Also note the \fI\-only\fP option.) +e.g., \fI\-\-bsd\fP, \fI\-\-no-bsd\fP. (Also note the \fI\-\-only\fP option.) .SH BUGS Unlike the systems being simulated, \fIbsod\fP does not require a reboot after running. diff --git a/hacks/bubbles.man b/hacks/bubbles.man index 25d77f69..5e1ac068 100644 --- a/hacks/bubbles.man +++ b/hacks/bubbles.man @@ -3,8 +3,10 @@ bubbles \- frying pan / soft drink simulation .SH SYNOPSIS .B bubbles -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-simple] [\-broken] [\-3D] [\-rise|\-drop] [-trails] -[\-fps] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] [\-\-visual \fIvisual\fP] [\-\-simple] [\-\-broken] [\-3D] [\-\-rise|\-\-drop] [-trails] +[\-\-fps] .SH DESCRIPTION \fIBubbles\fP sprays lots of little random bubbles all over the window which then grow until they reach their maximum size and go pop. The inspiration @@ -17,43 +19,46 @@ Depending on how your .I bubbles was compiled, it accepts the following options: .TP 8 -.B \-foreground -Colour of circles if \fI\-simple\fP mode is selected. +.B \-\-foreground +Colour of circles if \fI\-\-simple\fP mode is selected. .TP 8 -.B \-background +.B \-\-background Colour of window background. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-delay microseconds +.B \-\-delay microseconds How much of a delay should be introduced between steps of the animation. Default 800, or about 800 microsecond. Actually, this is the delay between each group of 15 new bubbles since such a delay between each step results in a very slow animation rate. .TP 8 -.B \-nodelay -Same as \fI\-delay 0\fP. +.B \-\-nodelay +Same as \fI\-\-delay 0\fP. .TP 8 -.B \-simple +.B \-\-simple Don't use the default fancy pixmap bubbles. Just draw circles instead. This may give more bearable performance if your hardware wasn't made for this sort of thing. .TP 8 -.B \-broken +.B \-\-broken Don't hide bubbles when they pop. This was a bug during development but the results were actually quite attractive. .TP 8 @@ -66,25 +71,25 @@ whole thing looks more realistic but I find it attracts attention to the flickering of each bubble as they are move and are redrawn. Your mileage may vary. .TP 8 -.B \-quiet +.B \-\-quiet Don't print messages explaining why one or several command line options were ignored. This is disabled by default. .TP 8 -.B \-rise | \-drop +.B \-\-rise | \-\-drop .TP 8 -.B \-trails +.B \-\-trails .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH NOTES If you find the pace of things too slow, remember that there is a delay -even though you specify no \fI\-delay\fP option. Try using \fI\-nodelay\fP +even though you specify no \fI\-\-delay\fP option. Try using \fI\-\-nodelay\fP although beware of the effects of irritation of other users if you're on a shared system as you bleed their CPU time away. Some tools to assist in creation of new bubbles are included in the source -distribution. These can either be loaded with the \fI\-file\fP or -\fI\-directory\fP options (if available) or they can be used in place +distribution. These can either be loaded with the \fI\-\-file\fP or +\fI\-\-directory\fP options (if available) or they can be used in place of the distributed default bubble (bubble_default.c). You might like to copy these scripts to a permanent location and use them. Read bubbles.README. @@ -101,7 +106,7 @@ The movement of the bubbles looks jerky if an incomplete set of bubbles is used. The hide/display algorithm could do with some work to avoid flickering -when \fI\-nodelay\fP is set. +when \fI\-\-nodelay\fP is set. .SH ENVIRONMENT .PP .TP 8 @@ -111,6 +116,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/bumps.man b/hacks/bumps.man index 717c1c37..117bc93a 100644 --- a/hacks/bumps.man +++ b/hacks/bumps.man @@ -3,17 +3,18 @@ bumps \- move distorting spotlight around desktop .SH SYNOPSIS .B bumps -[\-display \fIhost:display.screen\fP] -[\-foreground \fIcolor\fP] -[\-background \fIcolor\fP] -[\-window] -[\-root] -[\-mono] -[\-install] -[\-visual \fIvisual\fP] -[\-delay \fIusecs\fP] -[\-duration \fIsecs\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-mono] +[\-\-install] +[\-\-visual \fIvisual\fP] +[\-\-delay \fIusecs\fP] +[\-\-duration \fIsecs\fP] +[\-\-fps] .SH DESCRIPTION The \fIbumps\fP program takes an image and exposes small, distorted sections of it as if through an odd wandering spotlight beam. @@ -30,29 +31,32 @@ for more details. .I bumps accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-delay \fImicroseconds\fP +.B \-\-delay \fImicroseconds\fP Slow it down. .TP 8 -.B \-duration \fIseconds\fP +.B \-\-duration \fIseconds\fP How long to run before loading a new image. Default 120 seconds. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -63,6 +67,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/ccurve.man b/hacks/ccurve.man index d2b8ae84..8c5b0537 100644 --- a/hacks/ccurve.man +++ b/hacks/ccurve.man @@ -3,38 +3,42 @@ ccurve \- self-similar linear fractals. .SH SYNOPSIS .B ccurve -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-pause \fInumber\fP] -[\-limit \fInumber\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-pause \fInumber\fP] +[\-\-limit \fInumber\fP] +[\-\-fps] .SH DESCRIPTION Generates self-similar linear fractals, including the classic ``C Curve.'' .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Delay. 0 - 60. Default: 1. .TP 8 -.B \-pause \fInumber\fP +.B \-\-pause \fInumber\fP Duration. 1 - 60. Default: 3. .TP 8 -.B \-limit \fInumber\fP +.B \-\-limit \fInumber\fP Density. 3 - 300000. Default: 200000. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -45,6 +49,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/celtic.man b/hacks/celtic.man index 06b81d70..a0218c1a 100644 --- a/hacks/celtic.man +++ b/hacks/celtic.man @@ -3,42 +3,46 @@ celtic \- draws celtic cross-stich patterns .SH SYNOPSIS .B ifs -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-delay2 \fInumber\fP] -[\-ncolors \fInumber\fP] -[\-graph \fImode\fP] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-delay2 \fInumber\fP] +[\-\-ncolors \fInumber\fP] +[\-\-graph \fImode\fP] +[\-\-fps] .SH DESCRIPTION The \fIceltic\fP program repeatedly draws random cross-stitch patterns. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 10000. .TP 8 -.B \-delay2 \fInumber\fP +.B \-\-delay2 \fInumber\fP Delay between patterns, in seconds. Default: 5. .TP 8 -.B \-ncolors \fInumber\fP +.B \-\-ncolors \fInumber\fP Number of colours to use. Default: 20. .TP 8 -.B \-graph +.B \-\-graph Whether to render the underlying graph. Default: no. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -49,6 +53,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/cloudlife.man b/hacks/cloudlife.man index c94d77b3..6b2326e7 100644 --- a/hacks/cloudlife.man +++ b/hacks/cloudlife.man @@ -3,9 +3,11 @@ cloudlife \- a cellular automaton based on Conway's Life .SH SYNOPSIS .B cloudlife -[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-cycle-delay \fImicroseconds\fP] [\-cycle-colors \fIinteger\fP][\-cell-size \fIinteger\fP] [\-initial-density \fIinteger\fP] [\-max-age \fIinteger\fP] +[\-\-display \fIhost:display.screen\fP] [\-\-foreground \fIcolor\fP] +[\-\-background \fIcolor\fP] [\-\-window] [\-\-root] +[\-\-window\-id \fInumber\fP][\-\-mono] [\-\-install] [\-\-visual \fIvisual\fP] [\-\-ncolors \fIinteger\fP] [\-\-cycle-delay \fImicroseconds\fP] [\-\-cycle-colors \fIinteger\fP][\-\-cell-size \fIinteger\fP] [\-\-initial-density \fIinteger\fP] [\-\-max-age \fIinteger\fP] -[\-fps] +[\-\-fps] .SH DESCRIPTION The \fIcloudlife\fP program draws a cellular automaton based on Conway's Life, except that @@ -15,44 +17,47 @@ cell is drawn every tick. .I cloudlife accepts the following options: .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-mono +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-mono If on a color display, pretend we're on a monochrome display. .TP 8 -.B \-install +.B \-\-install Install a private colormap for the window. .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-cycle-delay \fIinteger\fP +.B \-\-cycle-delay \fIinteger\fP Time in microseconds to sleep between ticks. Default 25000. .TP 8 -.B \-cycle-colors \fIinteger\fP +.B \-\-cycle-colors \fIinteger\fP How many ticks should elapse between cycling colors. 0 to disable color cycling. Default 2. .TP 8 -.B \-ncolors \fIinteger\fP +.B \-\-ncolors \fIinteger\fP How many colors should be used (if possible). Default 64. The colors are chosen randomly. .TP 8 -.B \-cell-size \fIinteger\fP +.B \-\-cell-size \fIinteger\fP Size of each cell, in powers of 2. Default 3 (8-pixel cells). .TP 8 -.B \-initial-density \fIinteger\fP +.B \-\-initial-density \fIinteger\fP Percentage of cells that are alive at start and when the field is repopulated. Default 30. .TP 8 -.B \-max-age \fIinteger\fP +.B \-\-max-age \fIinteger\fP Maximum age for a cell. Default 64. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -63,6 +68,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1), diff --git a/hacks/compass.man b/hacks/compass.man index 13ffde4b..3e959128 100644 --- a/hacks/compass.man +++ b/hacks/compass.man @@ -3,35 +3,39 @@ compass \- draws a spinning compass. .SH SYNOPSIS .B compass -[\-display \fIhost:display.screen\fP] -[\-visual \fIvisual\fP] -[\-window] -[\-root] -[\-delay \fInumber\fP] -[\-no-db] -[\-fps] +[\-\-display \fIhost:display.screen\fP] +[\-\-visual \fIvisual\fP] +[\-\-window] +[\-\-root] +[\-\-window\-id \fInumber\fP] +[\-\-delay \fInumber\fP] +[\-\-no-db] +[\-\-fps] .SH DESCRIPTION This draws a compass, with all elements spinning about randomly, for that ``lost and nauseous'' feeling. .SH OPTIONS .TP 8 -.B \-visual \fIvisual\fP +.B \-\-visual \fIvisual\fP Specify which visual to use. Legal values are the name of a visual class, or the id number (decimal or hex) of a specific visual. .TP 8 -.B \-window +.B \-\-window Draw on a newly-created window. This is the default. .TP 8 -.B \-root +.B \-\-root Draw on the root window. .TP 8 -.B \-delay \fInumber\fP +.B \-\-window\-id \fInumber\fP +Draw on the specified window. +.TP 8 +.B \-\-delay \fInumber\fP Per-frame delay, in microseconds. Default: 20000 (0.02 seconds.). .TP 8 -.B \-db | \-no-db +.B \-\-db | \-\-no-db Double Buffer. Boolean. .TP 8 -.B \-fps +.B \-\-fps Display the current frame rate and CPU load. .SH ENVIRONMENT .PP @@ -42,6 +46,9 @@ to get the default host and display number. .B XENVIRONMENT to get the name of a resource file that overrides the global resources stored in the RESOURCE_MANAGER property. +.TP 8 +.B XSCREENSAVER_WINDOW +The window ID to use with \fI\-\-root\fP. .SH SEE ALSO .BR X (1), .BR xscreensaver (1) diff --git a/hacks/config/abstractile.xml b/hacks/config/abstractile.xml index 8d8ac126..e411a126 100644 --- a/hacks/config/abstractile.xml +++ b/hacks/config/abstractile.xml @@ -2,30 +2,29 @@ - +