From 5971d63df629ce52a3c44770008ab1d9efcd47fd Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sat, 30 Nov 2013 15:51:10 +0200 Subject: [PATCH] Dawn of a new world --- .gitignore | 38 + COPYING | 675 +++++ Makefile.am | 35 + README | 43 + Xext/Makefile.am | 65 + Xext/bigreq.c | 101 + Xext/dpms.c | 453 ++++ Xext/dpmsproc.h | 15 + Xext/saver.c | 1427 ++++++++++ Xext/shape.c | 1241 +++++++++ Xext/shm.c | 991 +++++++ Xext/shmint.h | 43 + Xext/sleepuntil.c | 240 ++ Xext/sleepuntil.h | 42 + Xext/sync.c | 2456 +++++++++++++++++ Xext/xcmisc.c | 244 ++ Xext/xf86bigfont.c | 779 ++++++ Xext/xf86bigfontsrv.h | 33 + Xext/xres.c | 392 +++ Xext/xtest.c | 436 +++ autogen.sh | 10 + configure.ac | 687 +++++ damageext/Makefile.am | 8 + damageext/damageext.c | 515 ++++ damageext/damageext.h | 33 + damageext/damageextint.h | 91 + dbe/Makefile.am | 10 + dbe/dbe.c | 1829 +++++++++++++ dbe/dbestruct.h | 226 ++ dbe/midbe.c | 791 ++++++ dbe/midbe.h | 43 + dbe/midbestr.h | 93 + dix/Makefile.am | 33 + dix/atom.c | 212 ++ dix/colormap.c | 2555 ++++++++++++++++++ dix/cursor.c | 442 +++ dix/devices.c | 1363 ++++++++++ dix/dispatch.c | 3865 +++++++++++++++++++++++++++ dix/dispatch.h | 146 + dix/dixfonts.c | 2053 ++++++++++++++ dix/dixutils.c | 837 ++++++ dix/events.c | 3437 ++++++++++++++++++++++++ dix/extension.c | 404 +++ dix/ffs.c | 39 + dix/gc.c | 1275 +++++++++ dix/globals.c | 176 ++ dix/glyphcurs.c | 194 ++ dix/grabs.c | 404 +++ dix/initatoms.c | 153 ++ dix/main.c | 661 +++++ dix/pixmap.c | 143 + dix/privates.c | 340 +++ dix/property.c | 610 +++++ dix/resource.c | 844 ++++++ dix/strcasecmp.c | 48 + dix/swaprep.c | 1185 +++++++++ dix/swapreq.c | 1084 ++++++++ dix/tables.c | 985 +++++++ dix/window.c | 3362 +++++++++++++++++++++++ fb/Makefile.am | 45 + fb/fb.h | 1565 +++++++++++ fb/fb24_32.c | 586 ++++ fb/fb24_32.h | 44 + fb/fballpriv.c | 82 + fb/fbarc.c | 117 + fb/fbbits.c | 175 ++ fb/fbbits.h | 938 +++++++ fb/fbblt.c | 818 ++++++ fb/fbbltone.c | 840 ++++++ fb/fbcmap.c | 114 + fb/fbcompose.c | 4284 ++++++++++++++++++++++++++++++ fb/fbcopy.c | 584 ++++ fb/fbedge.c | 286 ++ fb/fbedgeimp.h | 138 + fb/fbfill.c | 204 ++ fb/fbfillrect.c | 103 + fb/fbfillsp.c | 93 + fb/fbgc.c | 321 +++ fb/fbgetsp.c | 73 + fb/fbglyph.c | 451 ++++ fb/fbimage.c | 295 ++ fb/fbline.c | 160 ++ fb/fboverlay.c | 424 +++ fb/fboverlay.h | 116 + fb/fbpict.c | 1240 +++++++++ fb/fbpict.h | 610 +++++ fb/fbpixmap.c | 365 +++ fb/fbpoint.c | 165 ++ fb/fbpush.c | 202 ++ fb/fbrop.h | 137 + fb/fbscreen.c | 214 ++ fb/fbseg.c | 677 +++++ fb/fbsetsp.c | 93 + fb/fbsolid.c | 187 ++ fb/fbstipple.c | 277 ++ fb/fbtile.c | 161 ++ fb/fbtrap.c | 239 ++ fb/fbutil.c | 293 ++ fb/fbwindow.c | 314 +++ include/Makefile.am | 12 + include/closestr.h | 156 ++ include/closure.h | 57 + include/colormap.h | 182 ++ include/colormapst.h | 133 + include/cursor.h | 138 + include/cursorstr.h | 91 + include/dix-config.h.in | 257 ++ include/dix.h | 729 +++++ include/dixevents.h | 97 + include/dixfont.h | 150 ++ include/dixfontstr.h | 93 + include/dixgrabs.h | 58 + include/dixstruct.h | 195 ++ include/exevents.h | 182 ++ include/extension.h | 71 + include/extinit.h | 166 ++ include/extnsionst.h | 143 + include/gc.h | 176 ++ include/gcstruct.h | 322 +++ include/globals.h | 82 + include/input.h | 333 +++ include/inputstr.h | 297 +++ include/kdrive-config.h.in | 21 + include/misc.h | 298 +++ include/miscstruct.h | 78 + include/opaque.h | 75 + include/os.h | 407 +++ include/pixmap.h | 108 + include/pixmapstr.h | 91 + include/property.h | 72 + include/propertyst.h | 66 + include/region.h | 53 + include/regionstr.h | 266 ++ include/resource.h | 256 ++ include/screenint.h | 106 + include/scrnintstr.h | 532 ++++ include/selection.h | 68 + include/servermd.h | 397 +++ include/site.h | 130 + include/swaprep.h | 310 +++ include/swapreq.h | 119 + include/validate.h | 40 + include/window.h | 264 ++ include/windowstr.h | 191 ++ kdrive/Makefile.am | 19 + kdrive/fbdev/Makefile.am | 28 + kdrive/fbdev/fbdev.c | 784 ++++++ kdrive/fbdev/fbdev.h | 80 + kdrive/fbdev/fbinit.c | 100 + kdrive/linux/Makefile.am | 20 + kdrive/linux/keyboard.c | 469 ++++ kdrive/linux/linux.c | 342 +++ kdrive/linux/mouse.c | 943 +++++++ kdrive/src/Makefile.am | 22 + kdrive/src/kcmap.c | 241 ++ kdrive/src/kdrive.c | 1230 +++++++++ kdrive/src/kdrive.h | 419 +++ kdrive/src/kinfo.c | 137 + kdrive/src/kinput.c | 1578 +++++++++++ kdrive/src/kkeymap.h | 52 + kdrive/src/kmap.c | 151 ++ kdrive/src/kmode.c | 270 ++ kdrive/src/kshadow.c | 77 + kdrive/vesa/Makefile.am | 34 + kdrive/vesa/vbe.c | 692 +++++ kdrive/vesa/vbe.h | 145 + kdrive/vesa/vesa.c | 1696 ++++++++++++ kdrive/vesa/vesa.h | 139 + kdrive/vesa/vesainit.c | 106 + kdrive/vesa/vga.c | 224 ++ kdrive/vesa/vga.h | 47 + kdrive/vesa/vm86.c | 754 ++++++ kdrive/vesa/vm86.h | 144 + loc.sh | 3 + m4/ax_check_compile_flag.m4 | 72 + m4/ax_check_link_flag.m4 | 71 + m4/dir.m4 | 14 + mi/Makefile.am | 61 + mi/mi.h | 588 ++++ mi/miarc.c | 3718 ++++++++++++++++++++++++++ mi/mibank.c | 2455 +++++++++++++++++ mi/mibank.h | 118 + mi/mibitblt.c | 843 ++++++ mi/micmap.c | 653 +++++ mi/micmap.h | 64 + mi/micoord.h | 70 + mi/micursor.c | 75 + mi/midash.c | 313 +++ mi/midispcur.c | 813 ++++++ mi/mieq.c | 193 ++ mi/miexpose.c | 545 ++++ mi/mifillarc.c | 815 ++++++ mi/mifillarc.h | 214 ++ mi/mifillrct.c | 142 + mi/mifpoly.h | 109 + mi/mifpolycon.c | 282 ++ mi/migc.c | 299 +++ mi/migc.h | 72 + mi/miglblt.c | 253 ++ mi/miinitext.c | 234 ++ mi/miline.h | 172 ++ mi/mipointer.c | 527 ++++ mi/mipointer.h | 151 ++ mi/mipointrst.h | 62 + mi/mipoly.c | 127 + mi/mipoly.h | 215 ++ mi/mipolycon.c | 246 ++ mi/mipolygen.c | 230 ++ mi/mipolypnt.c | 123 + mi/mipolyrect.c | 191 ++ mi/mipolyseg.c | 83 + mi/mipolytext.c | 152 ++ mi/mipolyutil.c | 399 +++ mi/mipushpxl.c | 274 ++ mi/miregion.c | 2181 +++++++++++++++ mi/miscanfill.h | 147 + mi/miscrinit.c | 330 +++ mi/mispans.c | 542 ++++ mi/mispans.h | 98 + mi/misprite.c | 778 ++++++ mi/misprite.h | 94 + mi/mispritest.h | 127 + mi/mistruct.h | 63 + mi/mivalidate.h | 53 + mi/mivaltree.c | 770 ++++++ mi/miwideline.c | 2231 ++++++++++++++++ mi/miwideline.h | 222 ++ mi/miwindow.c | 850 ++++++ mi/mizerarc.c | 853 ++++++ mi/mizerarc.h | 132 + mi/mizerclip.c | 635 +++++ mi/mizerline.c | 378 +++ miext/Makefile.am | 2 + miext/damage/Makefile.am | 10 + miext/damage/damage.c | 1922 ++++++++++++++ miext/damage/damage.h | 81 + miext/damage/damagestr.h | 114 + miext/shadow/Makefile.am | 28 + miext/shadow/shadow.c | 257 ++ miext/shadow/shadow.h | 163 ++ miext/shadow/shalloc.c | 51 + miext/shadow/shpacked.c | 127 + miext/shadow/shplanar.c | 195 ++ miext/shadow/shplanar8.c | 184 ++ miext/shadow/shrot16pack.c | 31 + miext/shadow/shrot16pack_180.c | 32 + miext/shadow/shrot16pack_270.c | 32 + miext/shadow/shrot16pack_270YX.c | 32 + miext/shadow/shrot16pack_90.c | 32 + miext/shadow/shrot16pack_90YX.c | 32 + miext/shadow/shrot32pack.c | 31 + miext/shadow/shrot32pack_180.c | 32 + miext/shadow/shrot32pack_270.c | 32 + miext/shadow/shrot32pack_90.c | 32 + miext/shadow/shrot8pack.c | 31 + miext/shadow/shrot8pack_180.c | 32 + miext/shadow/shrot8pack_270.c | 32 + miext/shadow/shrot8pack_90.c | 32 + miext/shadow/shrotate.c | 333 +++ miext/shadow/shrotpack.h | 207 ++ miext/shadow/shrotpackYX.h | 167 ++ os/Makefile.am | 33 + os/WaitFor.c | 670 +++++ os/access.c | 1951 ++++++++++++++ os/auth.c | 236 ++ os/connection.c | 996 +++++++ os/io.c | 1026 +++++++ os/log.c | 194 ++ os/mitauth.c | 162 ++ os/oscolor.c | 1598 +++++++++++ os/osdep.h | 274 ++ os/osinit.c | 199 ++ os/strlcat.c | 56 + os/strlcpy.c | 51 + os/utils.c | 1640 ++++++++++++ os/xauembed.c | 120 + os/xdmauth.c | 501 ++++ os/xdmcp.c | 1618 +++++++++++ os/xstrans.c | 30 + randr/Makefile.am | 18 + randr/mirandr.c | 144 + randr/randr.c | 495 ++++ randr/randrstr.h | 801 ++++++ randr/rrcrtc.c | 865 ++++++ randr/rrdispatch.c | 207 ++ randr/rrinfo.c | 335 +++ randr/rrmode.c | 254 ++ randr/rroutput.c | 452 ++++ randr/rrpointer.c | 151 ++ randr/rrproperty.c | 637 +++++ randr/rrscreen.c | 942 +++++++ randr/rrsdispatch.c | 302 +++ randr/rrxinerama.c | 437 +++ render/Makefile.am | 22 + render/animcur.c | 388 +++ render/filter.c | 336 +++ render/glyph.c | 729 +++++ render/glyphstr.h | 148 ++ render/miglyph.c | 250 ++ render/miindex.c | 359 +++ render/mipict.c | 609 +++++ render/mipict.h | 191 ++ render/mirect.c | 179 ++ render/mitrap.c | 189 ++ render/mitri.c | 190 ++ render/picture.c | 1846 +++++++++++++ render/picture.h | 246 ++ render/picturestr.h | 608 +++++ render/render.c | 2697 +++++++++++++++++++ render/renderedge.c | 190 ++ render/renderedge.h | 113 + xfixes/Makefile.am | 12 + xfixes/cursor.c | 1027 +++++++ xfixes/region.c | 857 ++++++ xfixes/saveset.c | 77 + xfixes/select.c | 257 ++ xfixes/xfixes.c | 259 ++ xfixes/xfixes.h | 52 + xfixes/xfixesint.h | 281 ++ 319 files changed, 138294 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 Makefile.am create mode 100644 README create mode 100644 Xext/Makefile.am create mode 100644 Xext/bigreq.c create mode 100644 Xext/dpms.c create mode 100644 Xext/dpmsproc.h create mode 100644 Xext/saver.c create mode 100644 Xext/shape.c create mode 100644 Xext/shm.c create mode 100644 Xext/shmint.h create mode 100644 Xext/sleepuntil.c create mode 100644 Xext/sleepuntil.h create mode 100644 Xext/sync.c create mode 100644 Xext/xcmisc.c create mode 100644 Xext/xf86bigfont.c create mode 100644 Xext/xf86bigfontsrv.h create mode 100644 Xext/xres.c create mode 100644 Xext/xtest.c create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 damageext/Makefile.am create mode 100644 damageext/damageext.c create mode 100644 damageext/damageext.h create mode 100644 damageext/damageextint.h create mode 100644 dbe/Makefile.am create mode 100644 dbe/dbe.c create mode 100644 dbe/dbestruct.h create mode 100644 dbe/midbe.c create mode 100644 dbe/midbe.h create mode 100644 dbe/midbestr.h create mode 100644 dix/Makefile.am create mode 100644 dix/atom.c create mode 100644 dix/colormap.c create mode 100644 dix/cursor.c create mode 100644 dix/devices.c create mode 100644 dix/dispatch.c create mode 100644 dix/dispatch.h create mode 100644 dix/dixfonts.c create mode 100644 dix/dixutils.c create mode 100644 dix/events.c create mode 100644 dix/extension.c create mode 100644 dix/ffs.c create mode 100644 dix/gc.c create mode 100644 dix/globals.c create mode 100644 dix/glyphcurs.c create mode 100644 dix/grabs.c create mode 100644 dix/initatoms.c create mode 100644 dix/main.c create mode 100644 dix/pixmap.c create mode 100644 dix/privates.c create mode 100644 dix/property.c create mode 100644 dix/resource.c create mode 100644 dix/strcasecmp.c create mode 100644 dix/swaprep.c create mode 100644 dix/swapreq.c create mode 100644 dix/tables.c create mode 100644 dix/window.c create mode 100644 fb/Makefile.am create mode 100644 fb/fb.h create mode 100644 fb/fb24_32.c create mode 100644 fb/fb24_32.h create mode 100644 fb/fballpriv.c create mode 100644 fb/fbarc.c create mode 100644 fb/fbbits.c create mode 100644 fb/fbbits.h create mode 100644 fb/fbblt.c create mode 100644 fb/fbbltone.c create mode 100644 fb/fbcmap.c create mode 100644 fb/fbcompose.c create mode 100644 fb/fbcopy.c create mode 100644 fb/fbedge.c create mode 100644 fb/fbedgeimp.h create mode 100644 fb/fbfill.c create mode 100644 fb/fbfillrect.c create mode 100644 fb/fbfillsp.c create mode 100644 fb/fbgc.c create mode 100644 fb/fbgetsp.c create mode 100644 fb/fbglyph.c create mode 100644 fb/fbimage.c create mode 100644 fb/fbline.c create mode 100644 fb/fboverlay.c create mode 100644 fb/fboverlay.h create mode 100644 fb/fbpict.c create mode 100644 fb/fbpict.h create mode 100644 fb/fbpixmap.c create mode 100644 fb/fbpoint.c create mode 100644 fb/fbpush.c create mode 100644 fb/fbrop.h create mode 100644 fb/fbscreen.c create mode 100644 fb/fbseg.c create mode 100644 fb/fbsetsp.c create mode 100644 fb/fbsolid.c create mode 100644 fb/fbstipple.c create mode 100644 fb/fbtile.c create mode 100644 fb/fbtrap.c create mode 100644 fb/fbutil.c create mode 100644 fb/fbwindow.c create mode 100644 include/Makefile.am create mode 100644 include/closestr.h create mode 100644 include/closure.h create mode 100644 include/colormap.h create mode 100644 include/colormapst.h create mode 100644 include/cursor.h create mode 100644 include/cursorstr.h create mode 100644 include/dix-config.h.in create mode 100644 include/dix.h create mode 100644 include/dixevents.h create mode 100644 include/dixfont.h create mode 100644 include/dixfontstr.h create mode 100644 include/dixgrabs.h create mode 100644 include/dixstruct.h create mode 100644 include/exevents.h create mode 100644 include/extension.h create mode 100644 include/extinit.h create mode 100644 include/extnsionst.h create mode 100644 include/gc.h create mode 100644 include/gcstruct.h create mode 100644 include/globals.h create mode 100644 include/input.h create mode 100644 include/inputstr.h create mode 100644 include/kdrive-config.h.in create mode 100644 include/misc.h create mode 100644 include/miscstruct.h create mode 100644 include/opaque.h create mode 100644 include/os.h create mode 100644 include/pixmap.h create mode 100644 include/pixmapstr.h create mode 100644 include/property.h create mode 100644 include/propertyst.h create mode 100644 include/region.h create mode 100644 include/regionstr.h create mode 100644 include/resource.h create mode 100644 include/screenint.h create mode 100644 include/scrnintstr.h create mode 100644 include/selection.h create mode 100644 include/servermd.h create mode 100644 include/site.h create mode 100644 include/swaprep.h create mode 100644 include/swapreq.h create mode 100644 include/validate.h create mode 100644 include/window.h create mode 100644 include/windowstr.h create mode 100644 kdrive/Makefile.am create mode 100644 kdrive/fbdev/Makefile.am create mode 100644 kdrive/fbdev/fbdev.c create mode 100644 kdrive/fbdev/fbdev.h create mode 100644 kdrive/fbdev/fbinit.c create mode 100644 kdrive/linux/Makefile.am create mode 100644 kdrive/linux/keyboard.c create mode 100644 kdrive/linux/linux.c create mode 100644 kdrive/linux/mouse.c create mode 100644 kdrive/src/Makefile.am create mode 100644 kdrive/src/kcmap.c create mode 100644 kdrive/src/kdrive.c create mode 100644 kdrive/src/kdrive.h create mode 100644 kdrive/src/kinfo.c create mode 100644 kdrive/src/kinput.c create mode 100644 kdrive/src/kkeymap.h create mode 100644 kdrive/src/kmap.c create mode 100644 kdrive/src/kmode.c create mode 100644 kdrive/src/kshadow.c create mode 100644 kdrive/vesa/Makefile.am create mode 100644 kdrive/vesa/vbe.c create mode 100644 kdrive/vesa/vbe.h create mode 100644 kdrive/vesa/vesa.c create mode 100644 kdrive/vesa/vesa.h create mode 100644 kdrive/vesa/vesainit.c create mode 100644 kdrive/vesa/vga.c create mode 100644 kdrive/vesa/vga.h create mode 100644 kdrive/vesa/vm86.c create mode 100644 kdrive/vesa/vm86.h create mode 100755 loc.sh create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_check_link_flag.m4 create mode 100644 m4/dir.m4 create mode 100644 mi/Makefile.am create mode 100644 mi/mi.h create mode 100644 mi/miarc.c create mode 100644 mi/mibank.c create mode 100644 mi/mibank.h create mode 100644 mi/mibitblt.c create mode 100644 mi/micmap.c create mode 100644 mi/micmap.h create mode 100644 mi/micoord.h create mode 100644 mi/micursor.c create mode 100644 mi/midash.c create mode 100644 mi/midispcur.c create mode 100644 mi/mieq.c create mode 100644 mi/miexpose.c create mode 100644 mi/mifillarc.c create mode 100644 mi/mifillarc.h create mode 100644 mi/mifillrct.c create mode 100644 mi/mifpoly.h create mode 100644 mi/mifpolycon.c create mode 100644 mi/migc.c create mode 100644 mi/migc.h create mode 100644 mi/miglblt.c create mode 100644 mi/miinitext.c create mode 100644 mi/miline.h create mode 100644 mi/mipointer.c create mode 100644 mi/mipointer.h create mode 100644 mi/mipointrst.h create mode 100644 mi/mipoly.c create mode 100644 mi/mipoly.h create mode 100644 mi/mipolycon.c create mode 100644 mi/mipolygen.c create mode 100644 mi/mipolypnt.c create mode 100644 mi/mipolyrect.c create mode 100644 mi/mipolyseg.c create mode 100644 mi/mipolytext.c create mode 100644 mi/mipolyutil.c create mode 100644 mi/mipushpxl.c create mode 100644 mi/miregion.c create mode 100644 mi/miscanfill.h create mode 100644 mi/miscrinit.c create mode 100644 mi/mispans.c create mode 100644 mi/mispans.h create mode 100644 mi/misprite.c create mode 100644 mi/misprite.h create mode 100644 mi/mispritest.h create mode 100644 mi/mistruct.h create mode 100644 mi/mivalidate.h create mode 100644 mi/mivaltree.c create mode 100644 mi/miwideline.c create mode 100644 mi/miwideline.h create mode 100644 mi/miwindow.c create mode 100644 mi/mizerarc.c create mode 100644 mi/mizerarc.h create mode 100644 mi/mizerclip.c create mode 100644 mi/mizerline.c create mode 100644 miext/Makefile.am create mode 100644 miext/damage/Makefile.am create mode 100644 miext/damage/damage.c create mode 100644 miext/damage/damage.h create mode 100644 miext/damage/damagestr.h create mode 100644 miext/shadow/Makefile.am create mode 100644 miext/shadow/shadow.c create mode 100644 miext/shadow/shadow.h create mode 100644 miext/shadow/shalloc.c create mode 100644 miext/shadow/shpacked.c create mode 100644 miext/shadow/shplanar.c create mode 100644 miext/shadow/shplanar8.c create mode 100644 miext/shadow/shrot16pack.c create mode 100644 miext/shadow/shrot16pack_180.c create mode 100644 miext/shadow/shrot16pack_270.c create mode 100644 miext/shadow/shrot16pack_270YX.c create mode 100644 miext/shadow/shrot16pack_90.c create mode 100644 miext/shadow/shrot16pack_90YX.c create mode 100644 miext/shadow/shrot32pack.c create mode 100644 miext/shadow/shrot32pack_180.c create mode 100644 miext/shadow/shrot32pack_270.c create mode 100644 miext/shadow/shrot32pack_90.c create mode 100644 miext/shadow/shrot8pack.c create mode 100644 miext/shadow/shrot8pack_180.c create mode 100644 miext/shadow/shrot8pack_270.c create mode 100644 miext/shadow/shrot8pack_90.c create mode 100644 miext/shadow/shrotate.c create mode 100644 miext/shadow/shrotpack.h create mode 100644 miext/shadow/shrotpackYX.h create mode 100644 os/Makefile.am create mode 100644 os/WaitFor.c create mode 100644 os/access.c create mode 100644 os/auth.c create mode 100644 os/connection.c create mode 100644 os/io.c create mode 100644 os/log.c create mode 100644 os/mitauth.c create mode 100644 os/oscolor.c create mode 100644 os/osdep.h create mode 100644 os/osinit.c create mode 100644 os/strlcat.c create mode 100644 os/strlcpy.c create mode 100644 os/utils.c create mode 100644 os/xauembed.c create mode 100644 os/xdmauth.c create mode 100644 os/xdmcp.c create mode 100644 os/xstrans.c create mode 100644 randr/Makefile.am create mode 100644 randr/mirandr.c create mode 100644 randr/randr.c create mode 100644 randr/randrstr.h create mode 100644 randr/rrcrtc.c create mode 100644 randr/rrdispatch.c create mode 100644 randr/rrinfo.c create mode 100644 randr/rrmode.c create mode 100644 randr/rroutput.c create mode 100644 randr/rrpointer.c create mode 100644 randr/rrproperty.c create mode 100644 randr/rrscreen.c create mode 100644 randr/rrsdispatch.c create mode 100644 randr/rrxinerama.c create mode 100644 render/Makefile.am create mode 100644 render/animcur.c create mode 100644 render/filter.c create mode 100644 render/glyph.c create mode 100644 render/glyphstr.h create mode 100644 render/miglyph.c create mode 100644 render/miindex.c create mode 100644 render/mipict.c create mode 100644 render/mipict.h create mode 100644 render/mirect.c create mode 100644 render/mitrap.c create mode 100644 render/mitri.c create mode 100644 render/picture.c create mode 100644 render/picture.h create mode 100644 render/picturestr.h create mode 100644 render/render.c create mode 100644 render/renderedge.c create mode 100644 render/renderedge.h create mode 100644 xfixes/Makefile.am create mode 100644 xfixes/cursor.c create mode 100644 xfixes/region.c create mode 100644 xfixes/saveset.c create mode 100644 xfixes/select.c create mode 100644 xfixes/xfixes.c create mode 100644 xfixes/xfixes.h create mode 100644 xfixes/xfixesint.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e572126 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +Makefile +Makefile.in +.deps +.libs +.msg +*.lo +*.la +*.a +*.o +*~ +aclocal.m4 +autom4te.cache +m4/lt*m4 +m4/libtool.m4 +compile +config.guess +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +xorg-server.pc +stamp-h? +do-not-use-config.h +do-not-use-config.h.in +kdrive/fbdev/Xfbdev +kdrive/vesa/Xvesa +include/dix-config.h +include/kdrive-config.h +include/xkb-config.h +ylwrap +err +*rig +*rej diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..10926e8 --- /dev/null +++ b/COPYING @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..ad1e3e4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,35 @@ +ACLOCAL_AMFLAGS=-I m4 + +if DBE +DBE_DIR=dbe +endif + +SUBDIRS = \ + include \ + dix \ + fb \ + mi \ + Xext \ + miext \ + os \ + randr \ + render \ + $(DBE_DIR) \ + xfixes \ + damageext \ + kdrive + +DIST_SUBDIRS = \ + include \ + dix \ + fb \ + mi \ + Xext \ + miext \ + os \ + randr \ + render \ + dbe \ + xfixes \ + damageext \ + kdrive diff --git a/README b/README new file mode 100644 index 0000000..74daf74 --- /dev/null +++ b/README @@ -0,0 +1,43 @@ +Necromancy +========== + +We resurrected Xvesa from the depths of git history, and intend to maintain it with Xfbdev. + +This includes bugfixes, security fixes, and occasional new features if required. + + +Why? +---- + +The TinyX servers fill our needs while being a lot smaller than Xorg can be made. + + +Why 1.2.0 and not 1.3.0? +------------------------ + +As you know, Xvesa was killed in 1.4.0, so the latest released version would be 1.3.0. +However, they broke all input in 1.3.0 (keyboard and mouse), so the last working released +version is 1.2.0. + +There were also some changes later on that we disagree with (mandatory xinput & xkb). + + +Design choices +-------------- + +We aim for the smallest fully featured X server binary. Currently there are the vesa and +fbdev servers, but others may appear in the future (Xmodesetting?). + +- no xkb; it's bloat when console keymaps suffice +- no xinput +- no xinerama +- no gl +- TCP listening disabled by default, shadow FB enabled by default +... + + +Licensing +--------- + +While the original codebase is MIT, any changes here are GPLv3. Supporting closed devices +with this code is not a goal. diff --git a/Xext/Makefile.am b/Xext/Makefile.am new file mode 100644 index 0000000..6dc829e --- /dev/null +++ b/Xext/Makefile.am @@ -0,0 +1,65 @@ +# libXext.la: includes all extensions and should be linked into Xvfb, +# Xnest, Xdmx and Xprt +# libXextbuiltin.la: includes those extensions that are built directly into +# Xorg by default +# libXextmodule.la: includes those extensions that are built into a module +# that Xorg loads +noinst_LTLIBRARIES = libXext.la + +AM_CFLAGS = $(DIX_CFLAGS) + +# Sources always included in libXextbuiltin.la & libXext.la +BUILTIN_SRCS = \ + shape.c \ + sleepuntil.c \ + sleepuntil.h \ + xtest.c + +# Sources always included in libXextmodule.la & libXext.la +MODULE_SRCS = \ + bigreq.c \ + shape.c \ + sync.c \ + xcmisc.c + +# Optional sources included if extension enabled by configure.ac rules + +# MIT Shared Memory extension +MITSHM_SRCS = shm.c shmint.h +BUILTIN_SRCS += $(MITSHM_SRCS) + +# XResource extension: lets clients get data about per-client resource usage +RES_SRCS = xres.c +if RES +MODULE_SRCS += $(RES_SRCS) +endif + +# MIT ScreenSaver extension +SCREENSAVER_SRCS = saver.c +if SCREENSAVER +MODULE_SRCS += $(SCREENSAVER_SRCS) +endif + +# XF86 Big Font extension +BIGFONT_SRCS = xf86bigfont.c xf86bigfontsrv.h +if XF86BIGFONT +BUILTIN_SRCS += $(BIGFONT_SRCS) +endif + +# DPMS extension +DPMS_SRCS = dpms.c dpmsproc.h +if DPMSExtension +MODULE_SRCS += $(DPMS_SRCS) +endif + +# Now take all of the above, mix well, bake for 10 minutes and get libXext*.la + +libXext_la_SOURCES = $(BUILTIN_SRCS) $(MODULE_SRCS) + +EXTRA_DIST = \ + $(MITSHM_SRCS) \ + $(RES_SRCS) \ + $(SCREENSAVER_SRCS) \ + $(BIGFONT_SRCS) \ + $(DPMS_SRCS) + diff --git a/Xext/bigreq.c b/Xext/bigreq.c new file mode 100644 index 0000000..6c93052 --- /dev/null +++ b/Xext/bigreq.c @@ -0,0 +1,101 @@ +/* + +Copyright 1992, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include +#include "opaque.h" +#include "extinit.h" + +#if 0 +static unsigned char XBigReqCode; +#endif + +static void BigReqResetProc(ExtensionEntry * /* extEntry */ + ); + +static DISPATCH_PROC(ProcBigReqDispatch); + +void +BigReqExtensionInit(INITARGS) +{ +#if 0 + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(XBigReqExtensionName, 0, 0, + ProcBigReqDispatch, ProcBigReqDispatch, + BigReqResetProc, StandardMinorOpcode)) != 0) + XBigReqCode = (unsigned char) extEntry->base; +#else + (void) AddExtension(XBigReqExtensionName, 0, 0, + ProcBigReqDispatch, ProcBigReqDispatch, + BigReqResetProc, StandardMinorOpcode); +#endif + + DeclareExtensionSecurity(XBigReqExtensionName, TRUE); +} + + /*ARGSUSED*/ static void +BigReqResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static int +ProcBigReqDispatch(client) +ClientPtr client; +{ + REQUEST(xBigReqEnableReq); + xBigReqEnableReply rep = {0}; + + if (client->swapped) { + swaps(&stuff->length); + } + if (stuff->brReqType != X_BigReqEnable) + return BadRequest; + REQUEST_SIZE_MATCH(xBigReqEnableReq); + client->big_requests = TRUE; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.max_request_size = maxBigRequestSize; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.max_request_size); + } + WriteToClient(client, sizeof(xBigReqEnableReply), (char *) &rep); + return (client->noClientException); +} diff --git a/Xext/dpms.c b/Xext/dpms.c new file mode 100644 index 0000000..b75f482 --- /dev/null +++ b/Xext/dpms.c @@ -0,0 +1,453 @@ +/***************************************************************** + +Copyright (c) 1996 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* + * HISTORY + * + * @(#)RCSfile: dpms.c,v Revision: 1.1.4.5 (DEC) Date: 1996/03/04 15:27:00 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "opaque.h" +#define DPMS_SERVER +#include +#include +#include "dpmsproc.h" +#include "extinit.h" + +#if 0 +static unsigned char DPMSCode; +#endif +static DISPATCH_PROC(ProcDPMSDispatch); + +static DISPATCH_PROC(SProcDPMSDispatch); + +static DISPATCH_PROC(ProcDPMSGetVersion); + +static DISPATCH_PROC(SProcDPMSGetVersion); + +static DISPATCH_PROC(ProcDPMSGetTimeouts); + +static DISPATCH_PROC(SProcDPMSGetTimeouts); + +static DISPATCH_PROC(ProcDPMSSetTimeouts); + +static DISPATCH_PROC(SProcDPMSSetTimeouts); + +static DISPATCH_PROC(ProcDPMSEnable); + +static DISPATCH_PROC(SProcDPMSEnable); + +static DISPATCH_PROC(ProcDPMSDisable); + +static DISPATCH_PROC(SProcDPMSDisable); + +static DISPATCH_PROC(ProcDPMSForceLevel); + +static DISPATCH_PROC(SProcDPMSForceLevel); + +static DISPATCH_PROC(ProcDPMSInfo); + +static DISPATCH_PROC(SProcDPMSInfo); + +static DISPATCH_PROC(ProcDPMSCapable); + +static DISPATCH_PROC(SProcDPMSCapable); + +static void DPMSResetProc(ExtensionEntry * extEntry); + +void +DPMSExtensionInit(INITARGS) +{ +#if 0 + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(DPMSExtensionName, 0, 0, + ProcDPMSDispatch, SProcDPMSDispatch, + DPMSResetProc, StandardMinorOpcode))) + DPMSCode = (unsigned char) extEntry->base; +#else + (void) AddExtension(DPMSExtensionName, 0, 0, + ProcDPMSDispatch, SProcDPMSDispatch, + DPMSResetProc, StandardMinorOpcode); +#endif +} + + /*ARGSUSED*/ static void +DPMSResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static int +ProcDPMSGetVersion(client) +ClientPtr client; +{ + /* REQUEST(xDPMSGetVersionReq); */ + xDPMSGetVersionReply rep; + + + REQUEST_SIZE_MATCH(xDPMSGetVersionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = DPMSMajorVersion; + rep.minorVersion = DPMSMinorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + } + WriteToClient(client, sizeof(xDPMSGetVersionReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcDPMSCapable(register ClientPtr client) +{ + /* REQUEST(xDPMSCapableReq); */ + xDPMSCapableReply rep; + + + REQUEST_SIZE_MATCH(xDPMSCapableReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.capable = DPMSCapableFlag; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + } + WriteToClient(client, sizeof(xDPMSCapableReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcDPMSGetTimeouts(client) +ClientPtr client; +{ + /* REQUEST(xDPMSGetTimeoutsReq); */ + xDPMSGetTimeoutsReply rep; + + + REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.standby = DPMSStandbyTime / MILLI_PER_SECOND; + rep.suspend = DPMSSuspendTime / MILLI_PER_SECOND; + rep.off = DPMSOffTime / MILLI_PER_SECOND; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swaps(&rep.standby); + swaps(&rep.suspend); + swaps(&rep.off); + } + WriteToClient(client, sizeof(xDPMSGetTimeoutsReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcDPMSSetTimeouts(client) +ClientPtr client; +{ + REQUEST(xDPMSSetTimeoutsReq); + + REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq); + + if ((stuff->off != 0) && (stuff->off < stuff->suspend)) { + client->errorValue = stuff->off; + return BadValue; + } + if ((stuff->suspend != 0) && (stuff->suspend < stuff->standby)) { + client->errorValue = stuff->suspend; + return BadValue; + } + + DPMSStandbyTime = stuff->standby * MILLI_PER_SECOND; + DPMSSuspendTime = stuff->suspend * MILLI_PER_SECOND; + DPMSOffTime = stuff->off * MILLI_PER_SECOND; + SetScreenSaverTimer(); + + return (client->noClientException); +} + +static int +ProcDPMSEnable(client) +ClientPtr client; +{ + /* REQUEST(xDPMSEnableReq); */ + + REQUEST_SIZE_MATCH(xDPMSEnableReq); + + if (DPMSCapableFlag) + DPMSEnabled = TRUE; + + return (client->noClientException); +} + +static int +ProcDPMSDisable(client) +ClientPtr client; +{ + /* REQUEST(xDPMSDisableReq); */ + + REQUEST_SIZE_MATCH(xDPMSDisableReq); + + DPMSSet(DPMSModeOn); + + DPMSEnabled = FALSE; + + return (client->noClientException); +} + +static int +ProcDPMSForceLevel(client) +ClientPtr client; +{ + REQUEST(xDPMSForceLevelReq); + + REQUEST_SIZE_MATCH(xDPMSForceLevelReq); + + if (!DPMSEnabled) + return BadMatch; + + if (stuff->level == DPMSModeOn) { + lastDeviceEventTime.milliseconds = GetTimeInMillis(); + } + else if (stuff->level == DPMSModeStandby) { + lastDeviceEventTime.milliseconds = GetTimeInMillis() - DPMSStandbyTime; + } + else if (stuff->level == DPMSModeSuspend) { + lastDeviceEventTime.milliseconds = GetTimeInMillis() - DPMSSuspendTime; + } + else if (stuff->level == DPMSModeOff) { + lastDeviceEventTime.milliseconds = GetTimeInMillis() - DPMSOffTime; + } + else { + client->errorValue = stuff->level; + return BadValue; + } + + DPMSSet(stuff->level); + + return (client->noClientException); +} + +static int +ProcDPMSInfo(register ClientPtr client) +{ + /* REQUEST(xDPMSInfoReq); */ + xDPMSInfoReply rep; + + + REQUEST_SIZE_MATCH(xDPMSInfoReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.power_level = DPMSPowerLevel; + rep.state = DPMSEnabled; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swaps(&rep.power_level); + } + WriteToClient(client, sizeof(xDPMSInfoReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcDPMSDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DPMSGetVersion: + return ProcDPMSGetVersion(client); + case X_DPMSCapable: + return ProcDPMSCapable(client); + case X_DPMSGetTimeouts: + return ProcDPMSGetTimeouts(client); + case X_DPMSSetTimeouts: + return ProcDPMSSetTimeouts(client); + case X_DPMSEnable: + return ProcDPMSEnable(client); + case X_DPMSDisable: + return ProcDPMSDisable(client); + case X_DPMSForceLevel: + return ProcDPMSForceLevel(client); + case X_DPMSInfo: + return ProcDPMSInfo(client); + default: + return BadRequest; + } +} + +static int +SProcDPMSGetVersion(client) +ClientPtr client; +{ + + REQUEST(xDPMSGetVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSGetVersionReq); + swaps(&stuff->majorVersion); + swaps(&stuff->minorVersion); + return ProcDPMSGetVersion(client); +} + +static int +SProcDPMSCapable(register ClientPtr client) +{ + REQUEST(xDPMSCapableReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSCapableReq); + + return ProcDPMSCapable(client); +} + +static int +SProcDPMSGetTimeouts(client) +ClientPtr client; +{ + REQUEST(xDPMSGetTimeoutsReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSGetTimeoutsReq); + + return ProcDPMSGetTimeouts(client); +} + +static int +SProcDPMSSetTimeouts(client) +ClientPtr client; +{ + REQUEST(xDPMSSetTimeoutsReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSSetTimeoutsReq); + + swaps(&stuff->standby); + swaps(&stuff->suspend); + swaps(&stuff->off); + return ProcDPMSSetTimeouts(client); +} + +static int +SProcDPMSEnable(client) +ClientPtr client; +{ + REQUEST(xDPMSEnableReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSEnableReq); + + return ProcDPMSEnable(client); +} + +static int +SProcDPMSDisable(client) +ClientPtr client; +{ + REQUEST(xDPMSDisableReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSDisableReq); + + return ProcDPMSDisable(client); +} + +static int +SProcDPMSForceLevel(client) +ClientPtr client; +{ + REQUEST(xDPMSForceLevelReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSForceLevelReq); + + swaps(&stuff->level); + + return ProcDPMSForceLevel(client); +} + +static int +SProcDPMSInfo(client) +ClientPtr client; +{ + REQUEST(xDPMSInfoReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDPMSInfoReq); + + return ProcDPMSInfo(client); +} + +static int +SProcDPMSDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_DPMSGetVersion: + return SProcDPMSGetVersion(client); + case X_DPMSCapable: + return SProcDPMSCapable(client); + case X_DPMSGetTimeouts: + return SProcDPMSGetTimeouts(client); + case X_DPMSSetTimeouts: + return SProcDPMSSetTimeouts(client); + case X_DPMSEnable: + return SProcDPMSEnable(client); + case X_DPMSDisable: + return SProcDPMSDisable(client); + case X_DPMSForceLevel: + return SProcDPMSForceLevel(client); + case X_DPMSInfo: + return SProcDPMSInfo(client); + default: + return BadRequest; + } +} diff --git a/Xext/dpmsproc.h b/Xext/dpmsproc.h new file mode 100644 index 0000000..46c65d4 --- /dev/null +++ b/Xext/dpmsproc.h @@ -0,0 +1,15 @@ + +/* Prototypes for functions that the DDX must provide */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef _DPMSPROC_H_ +#define _DPMSPROC_H_ + +void DPMSSet(int level); + +Bool DPMSSupported(void); + +#endif diff --git a/Xext/saver.c b/Xext/saver.c new file mode 100644 index 0000000..293f013 --- /dev/null +++ b/Xext/saver.c @@ -0,0 +1,1427 @@ +/* + * +Copyright (c) 1992 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + * + * Author: Keith Packard, MIT X Consortium + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" +#include +#include "gcstruct.h" +#include "cursorstr.h" +#include "colormapst.h" +#ifdef DPMSExtension +#define DPMS_SERVER +#include +#endif + +#include + +#include "extinit.h" + +#if 0 +static unsigned char ScreenSaverReqCode = 0; +#endif +static int ScreenSaverEventBase = 0; + +extern DISPATCH_PROC(ProcScreenSaverQueryInfo); + +static DISPATCH_PROC(ProcScreenSaverDispatch); + +static DISPATCH_PROC(ProcScreenSaverQueryVersion); + +static DISPATCH_PROC(ProcScreenSaverSelectInput); + +static DISPATCH_PROC(ProcScreenSaverSetAttributes); + +static DISPATCH_PROC(ProcScreenSaverUnsetAttributes); + +static DISPATCH_PROC(ProcScreenSaverSuspend); + +static DISPATCH_PROC(SProcScreenSaverDispatch); + +static DISPATCH_PROC(SProcScreenSaverQueryInfo); + +static DISPATCH_PROC(SProcScreenSaverQueryVersion); + +static DISPATCH_PROC(SProcScreenSaverSelectInput); + +static DISPATCH_PROC(SProcScreenSaverSetAttributes); + +static DISPATCH_PROC(SProcScreenSaverUnsetAttributes); + +static DISPATCH_PROC(SProcScreenSaverSuspend); + +static Bool ScreenSaverHandle(ScreenPtr /* pScreen */ , + int /* xstate */ , + Bool /* force */ + ); + +static Bool + CreateSaverWindow(ScreenPtr /* pScreen */ + ); + +static Bool + DestroySaverWindow(ScreenPtr /* pScreen */ + ); + +static void + UninstallSaverColormap(ScreenPtr /* pScreen */ + ); + +static void + CheckScreenPrivate(ScreenPtr /* pScreen */ + ); + +static void SScreenSaverNotifyEvent(xScreenSaverNotifyEvent * /* from */ , + xScreenSaverNotifyEvent * /* to */ + ); + +static void ScreenSaverResetProc(ExtensionEntry * /* extEntry */ + ); + +static RESTYPE SuspendType; /* resource type for suspension records */ + +typedef struct _ScreenSaverSuspension *ScreenSaverSuspensionPtr; + +/* List of clients that are suspending the screensaver. */ +static ScreenSaverSuspensionPtr suspendingClients = NULL; + +/* + * clientResource is a resource ID that's added when the record is + * allocated, so the record is freed and the screensaver resumed when + * the client disconnects. count is the number of times the client has + * requested the screensaver be suspended. + */ +typedef struct _ScreenSaverSuspension { + ScreenSaverSuspensionPtr next; + ClientPtr pClient; + XID clientResource; + int count; +} ScreenSaverSuspensionRec; + +static int ScreenSaverFreeSuspend(pointer /*value */ , + XID /* id */ + ); + +/* + * each screen has a list of clients requesting + * ScreenSaverNotify events. Each client has a resource + * for each screen it selects ScreenSaverNotify input for, + * this resource is used to delete the ScreenSaverNotifyRec + * entry from the per-screen queue. + */ + +static RESTYPE EventType; /* resource type for event masks */ + +typedef struct _ScreenSaverEvent *ScreenSaverEventPtr; + +typedef struct _ScreenSaverEvent { + ScreenSaverEventPtr next; + ClientPtr client; + ScreenPtr screen; + XID resource; + CARD32 mask; +} ScreenSaverEventRec; + +static int ScreenSaverFreeEvents(pointer /* value */ , + XID /* id */ + ); + +static Bool setEventMask(ScreenPtr /* pScreen */ , + ClientPtr /* client */ , + unsigned long /* mask */ + ); + +static unsigned long getEventMask(ScreenPtr /* pScreen */ , + ClientPtr /* client */ + ); + +/* + * when a client sets the screen saver attributes, a resource is + * kept to be freed when the client exits + */ + +static RESTYPE AttrType; /* resource type for attributes */ + +typedef struct _ScreenSaverAttr { + ScreenPtr screen; + ClientPtr client; + XID resource; + short x, y; + unsigned short width, height, borderWidth; + unsigned char class; + unsigned char depth; + VisualID visual; + CursorPtr pCursor; + PixmapPtr pBackgroundPixmap; + PixmapPtr pBorderPixmap; + Colormap colormap; + unsigned long mask; /* no pixmaps or cursors */ + unsigned long *values; +} ScreenSaverAttrRec, *ScreenSaverAttrPtr; + +static int ScreenSaverFreeAttr(pointer /* value */ , + XID /* id */ + ); + +static void FreeAttrs(ScreenSaverAttrPtr /* pAttr */ + ); + +static void FreeScreenAttr(ScreenSaverAttrPtr /* pAttr */ + ); + +static void + SendScreenSaverNotify(ScreenPtr /* pScreen */ , + int /* state */ , + Bool /* forced */ + ); + +typedef struct _ScreenSaverScreenPrivate { + ScreenSaverEventPtr events; + ScreenSaverAttrPtr attr; + Bool hasWindow; + Colormap installedMap; +} ScreenSaverScreenPrivateRec, *ScreenSaverScreenPrivatePtr; + +static ScreenSaverScreenPrivatePtr MakeScreenPrivate(ScreenPtr /* pScreen */ + ); + +static int ScreenPrivateIndex; + +#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr)(s)->devPrivates[ScreenPrivateIndex].ptr) +#define SetScreenPrivate(s,v) ((s)->devPrivates[ScreenPrivateIndex].ptr = (pointer) v); +#define SetupScreen(s) ScreenSaverScreenPrivatePtr pPriv = (s ? GetScreenPrivate(s) : NULL) + +#define New(t) (malloc(sizeof (t))) + +/**************** + * ScreenSaverExtensionInit + * + * Called from InitExtensions in main() or from QueryExtension() if the + * extension is dynamically loaded. + * + ****************/ + +void +ScreenSaverExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + + int i; + + ScreenPtr pScreen; + + AttrType = CreateNewResourceType(ScreenSaverFreeAttr); + EventType = CreateNewResourceType(ScreenSaverFreeEvents); + SuspendType = CreateNewResourceType(ScreenSaverFreeSuspend); + ScreenPrivateIndex = AllocateScreenPrivateIndex(); + + for (i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + SetScreenPrivate(pScreen, NULL); + } + if (AttrType && EventType && SuspendType && ScreenPrivateIndex != -1 && + (extEntry = AddExtension(ScreenSaverName, ScreenSaverNumberEvents, 0, + ProcScreenSaverDispatch, + SProcScreenSaverDispatch, ScreenSaverResetProc, + StandardMinorOpcode))) { +#if 0 + ScreenSaverReqCode = (unsigned char) extEntry->base; +#endif + ScreenSaverEventBase = extEntry->eventBase; + EventSwapVector[ScreenSaverEventBase] = + (EventSwapPtr) SScreenSaverNotifyEvent; + } +} + + /*ARGSUSED*/ static void +ScreenSaverResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static void +CheckScreenPrivate(pScreen) +ScreenPtr pScreen; +{ + SetupScreen(pScreen); + + if (!pPriv) + return; + if (!pPriv->attr && !pPriv->events && + !pPriv->hasWindow && pPriv->installedMap == None) { + free(pPriv); + SetScreenPrivate(pScreen, NULL); + savedScreenInfo[pScreen->myNum].ExternalScreenSaver = NULL; + } +} + +static ScreenSaverScreenPrivatePtr +MakeScreenPrivate(pScreen) +ScreenPtr pScreen; +{ + SetupScreen(pScreen); + + if (pPriv) + return pPriv; + pPriv = New(ScreenSaverScreenPrivateRec); + if (!pPriv) + return 0; + pPriv->events = 0; + pPriv->attr = 0; + pPriv->hasWindow = FALSE; + pPriv->installedMap = None; + SetScreenPrivate(pScreen, pPriv); + savedScreenInfo[pScreen->myNum].ExternalScreenSaver = ScreenSaverHandle; + return pPriv; +} + +static unsigned long +getEventMask(pScreen, client) +ScreenPtr pScreen; + +ClientPtr client; +{ + SetupScreen(pScreen); + ScreenSaverEventPtr pEv; + + if (!pPriv) + return 0; + for (pEv = pPriv->events; pEv; pEv = pEv->next) + if (pEv->client == client) + return pEv->mask; + return 0; +} + +static Bool +setEventMask(pScreen, client, mask) +ScreenPtr pScreen; + +ClientPtr client; + +unsigned long mask; +{ + SetupScreen(pScreen); + ScreenSaverEventPtr pEv, *pPrev; + + if (getEventMask(pScreen, client) == mask) + return TRUE; + if (!pPriv) { + pPriv = MakeScreenPrivate(pScreen); + if (!pPriv) + return FALSE; + } + for (pPrev = &pPriv->events; (pEv = *pPrev) != 0; pPrev = &pEv->next) + if (pEv->client == client) + break; + if (mask == 0) { + FreeResource(pEv->resource, EventType); + *pPrev = pEv->next; + free(pEv); + CheckScreenPrivate(pScreen); + } + else { + if (!pEv) { + pEv = New(ScreenSaverEventRec); + if (!pEv) { + CheckScreenPrivate(pScreen); + return FALSE; + } + *pPrev = pEv; + pEv->next = NULL; + pEv->client = client; + pEv->screen = pScreen; + pEv->resource = FakeClientID(client->index); + if (!AddResource(pEv->resource, EventType, (pointer) pEv)) + return FALSE; + } + pEv->mask = mask; + } + return TRUE; +} + +static void +FreeAttrs(pAttr) +ScreenSaverAttrPtr pAttr; +{ + PixmapPtr pPixmap; + + CursorPtr pCursor; + + if ((pPixmap = pAttr->pBackgroundPixmap) != 0) + (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap); + if ((pPixmap = pAttr->pBorderPixmap) != 0) + (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap); + if ((pCursor = pAttr->pCursor) != 0) + FreeCursor(pCursor, (Cursor) 0); +} + +static void +FreeScreenAttr(pAttr) +ScreenSaverAttrPtr pAttr; +{ + FreeAttrs(pAttr); + free(pAttr->values); + free(pAttr); +} + +static int +ScreenSaverFreeEvents(value, id) +pointer value; + +XID id; +{ + ScreenSaverEventPtr pOld = (ScreenSaverEventPtr) value; + + ScreenPtr pScreen = pOld->screen; + + SetupScreen(pScreen); + ScreenSaverEventPtr pEv, *pPrev; + + if (!pPriv) + return TRUE; + for (pPrev = &pPriv->events; (pEv = *pPrev) != 0; pPrev = &pEv->next) + if (pEv == pOld) + break; + if (!pEv) + return TRUE; + *pPrev = pEv->next; + free(pEv); + CheckScreenPrivate(pScreen); + return TRUE; +} + +static int +ScreenSaverFreeAttr(value, id) +pointer value; + +XID id; +{ + ScreenSaverAttrPtr pOldAttr = (ScreenSaverAttrPtr) value; + + ScreenPtr pScreen = pOldAttr->screen; + + SetupScreen(pScreen); + + if (!pPriv) + return TRUE; + if (pPriv->attr != pOldAttr) + return TRUE; + FreeScreenAttr(pOldAttr); + pPriv->attr = NULL; + if (pPriv->hasWindow) { + SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset); + SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverActive); + } + CheckScreenPrivate(pScreen); + return TRUE; +} + +static int +ScreenSaverFreeSuspend(pointer value, XID id) +{ + ScreenSaverSuspensionPtr data = (ScreenSaverSuspensionPtr) value; + + ScreenSaverSuspensionPtr *prev, this; + + /* Unlink and free the suspension record for the client */ + for (prev = &suspendingClients; (this = *prev); prev = &this->next) { + if (this == data) { + *prev = this->next; + free(this); + break; + } + } + + /* Reenable the screensaver if this was the last client suspending it. */ + if (screenSaverSuspended && suspendingClients == NULL) { + screenSaverSuspended = FALSE; + + /* The screensaver could be active, since suspending it (by design) + doesn't prevent it from being forceably activated */ +#ifdef DPMSExtension + if (screenIsSaved != SCREEN_SAVER_ON && DPMSPowerLevel == DPMSModeOn) +#else + if (screenIsSaved != SCREEN_SAVER_ON) +#endif + { + UpdateCurrentTimeIf(); + lastDeviceEventTime = currentTime; + SetScreenSaverTimer(); + } + } + + return Success; +} + +static void +SendScreenSaverNotify(pScreen, state, forced) +ScreenPtr pScreen; + +int state; + +Bool forced; +{ + ScreenSaverScreenPrivatePtr pPriv; + + ScreenSaverEventPtr pEv; + + unsigned long mask; + + xScreenSaverNotifyEvent ev; + + ClientPtr client; + + int kind; + + UpdateCurrentTimeIf(); + mask = ScreenSaverNotifyMask; + if (state == ScreenSaverCycle) + mask = ScreenSaverCycleMask; + pScreen = screenInfo.screens[pScreen->myNum]; + pPriv = GetScreenPrivate(pScreen); + if (!pPriv) + return; + if (pPriv->attr) + kind = ScreenSaverExternal; + else if (ScreenSaverBlanking != DontPreferBlanking) + kind = ScreenSaverBlanked; + else + kind = ScreenSaverInternal; + for (pEv = pPriv->events; pEv; pEv = pEv->next) { + client = pEv->client; + if (client->clientGone) + continue; + if (!(pEv->mask & mask)) + continue; + ev.type = ScreenSaverNotify + ScreenSaverEventBase; + ev.state = state; + ev.sequenceNumber = client->sequence; + ev.timestamp = currentTime.milliseconds; + ev.root = WindowTable[pScreen->myNum]->drawable.id; + ev.window = savedScreenInfo[pScreen->myNum].wid; + ev.kind = kind; + ev.forced = forced; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } +} + +static void +SScreenSaverNotifyEvent(from, to) +xScreenSaverNotifyEvent *from, *to; +{ + to->type = from->type; + to->state = from->state; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->root, to->root); + cpswapl(from->window, to->window); + to->kind = from->kind; + to->forced = from->forced; +} + +static void +UninstallSaverColormap(pScreen) +ScreenPtr pScreen; +{ + SetupScreen(pScreen); + ColormapPtr pCmap; + + if (pPriv && pPriv->installedMap != None) { + pCmap = (ColormapPtr) LookupIDByType(pPriv->installedMap, RT_COLORMAP); + if (pCmap) + (*pCmap->pScreen->UninstallColormap) (pCmap); + pPriv->installedMap = None; + CheckScreenPrivate(pScreen); + } +} + +static Bool +CreateSaverWindow(pScreen) +ScreenPtr pScreen; +{ + SetupScreen(pScreen); + ScreenSaverStuffPtr pSaver; + + ScreenSaverAttrPtr pAttr; + + WindowPtr pWin; + + int result; + + unsigned long mask; + + Colormap *installedMaps; + + int numInstalled; + + int i; + + Colormap wantMap; + + ColormapPtr pCmap; + + pSaver = &savedScreenInfo[pScreen->myNum]; + if (pSaver->pWindow) { + pSaver->pWindow = NullWindow; + FreeResource(pSaver->wid, RT_NONE); + if (pPriv) { + UninstallSaverColormap(pScreen); + pPriv->hasWindow = FALSE; + CheckScreenPrivate(pScreen); + } + } + + if (!pPriv || !(pAttr = pPriv->attr)) + return FALSE; + + pPriv->installedMap = None; + + if (GrabInProgress && GrabInProgress != pAttr->client->index) + return FALSE; + + pWin = CreateWindow(pSaver->wid, WindowTable[pScreen->myNum], + pAttr->x, pAttr->y, pAttr->width, pAttr->height, + pAttr->borderWidth, pAttr->class, + pAttr->mask, (XID *) pAttr->values, + pAttr->depth, serverClient, pAttr->visual, &result); + if (!pWin) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, pWin)) + return FALSE; + + mask = 0; + if (pAttr->pBackgroundPixmap) { + pWin->backgroundState = BackgroundPixmap; + pWin->background.pixmap = pAttr->pBackgroundPixmap; + pAttr->pBackgroundPixmap->refcnt++; + mask |= CWBackPixmap; + } + if (pAttr->pBorderPixmap) { + pWin->borderIsPixel = FALSE; + pWin->border.pixmap = pAttr->pBorderPixmap; + pAttr->pBorderPixmap->refcnt++; + mask |= CWBorderPixmap; + } + if (pAttr->pCursor) { + if (!pWin->optional) + if (!MakeWindowOptional(pWin)) { + FreeResource(pWin->drawable.id, RT_NONE); + return FALSE; + } + if (pWin->optional->cursor) + FreeCursor(pWin->optional->cursor, (Cursor) 0); + pWin->optional->cursor = pAttr->pCursor; + pAttr->pCursor->refcnt++; + pWin->cursorIsNone = FALSE; + CheckWindowOptionalNeed(pWin); + mask |= CWCursor; + } + if (mask) + (*pScreen->ChangeWindowAttributes) (pWin, mask); + + if (pAttr->colormap != None) + (void) ChangeWindowAttributes(pWin, CWColormap, &pAttr->colormap, + serverClient); + + MapWindow(pWin, serverClient); + + pPriv->hasWindow = TRUE; + pSaver->pWindow = pWin; + + /* check and install our own colormap if it isn't installed now */ + wantMap = wColormap(pWin); + if (wantMap == None) + return TRUE; + installedMaps = (Colormap *) ALLOCATE_LOCAL(pScreen->maxInstalledCmaps * + sizeof(Colormap)); + numInstalled = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pScreen, installedMaps); + for (i = 0; i < numInstalled; i++) + if (installedMaps[i] == wantMap) + break; + + DEALLOCATE_LOCAL((char *) installedMaps); + + if (i < numInstalled) + return TRUE; + + pCmap = (ColormapPtr) LookupIDByType(wantMap, RT_COLORMAP); + if (!pCmap) + return TRUE; + + pPriv->installedMap = wantMap; + + (*pCmap->pScreen->InstallColormap) (pCmap); + + return TRUE; +} + +static Bool +DestroySaverWindow(pScreen) +ScreenPtr pScreen; +{ + SetupScreen(pScreen); + ScreenSaverStuffPtr pSaver; + + if (!pPriv || !pPriv->hasWindow) + return FALSE; + + pSaver = &savedScreenInfo[pScreen->myNum]; + if (pSaver->pWindow) { + pSaver->pWindow = NullWindow; + FreeResource(pSaver->wid, RT_NONE); + } + pPriv->hasWindow = FALSE; + CheckScreenPrivate(pScreen); + UninstallSaverColormap(pScreen); + return TRUE; +} + +static Bool +ScreenSaverHandle(pScreen, xstate, force) +ScreenPtr pScreen; + +int xstate; + +Bool force; +{ + int state = 0; + + Bool ret = FALSE; + + ScreenSaverScreenPrivatePtr pPriv; + + switch (xstate) { + case SCREEN_SAVER_ON: + state = ScreenSaverOn; + ret = CreateSaverWindow(pScreen); + break; + case SCREEN_SAVER_OFF: + state = ScreenSaverOff; + ret = DestroySaverWindow(pScreen); + break; + case SCREEN_SAVER_CYCLE: + state = ScreenSaverCycle; + pPriv = GetScreenPrivate(pScreen); + if (pPriv && pPriv->hasWindow) + ret = TRUE; + + } + SendScreenSaverNotify(pScreen, state, force); + return ret; +} + +static int +ProcScreenSaverQueryVersion(client) +ClientPtr client; +{ + xScreenSaverQueryVersionReply rep; + + + REQUEST_SIZE_MATCH(xScreenSaverQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = ScreenSaverMajorVersion; + rep.minorVersion = ScreenSaverMinorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + WriteToClient(client, sizeof(xScreenSaverQueryVersionReply), (char *) &rep); + return (client->noClientException); +} + +int +ProcScreenSaverQueryInfo(client) +ClientPtr client; +{ + REQUEST(xScreenSaverQueryInfoReq); + xScreenSaverQueryInfoReply rep; + + + ScreenSaverStuffPtr pSaver; + + DrawablePtr pDraw; + + CARD32 lastInput; + + ScreenSaverScreenPrivatePtr pPriv; + + REQUEST_SIZE_MATCH(xScreenSaverQueryInfoReq); + pDraw = (DrawablePtr) LookupDrawable(stuff->drawable, client); + if (!pDraw) + return BadDrawable; + + pSaver = &savedScreenInfo[pDraw->pScreen->myNum]; + pPriv = GetScreenPrivate(pDraw->pScreen); + + UpdateCurrentTime(); + lastInput = GetTimeInMillis() - lastDeviceEventTime.milliseconds; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.window = pSaver->wid; + if (screenIsSaved != SCREEN_SAVER_OFF) { + rep.state = ScreenSaverOn; + if (ScreenSaverTime) + rep.tilOrSince = lastInput - ScreenSaverTime; + else + rep.tilOrSince = 0; + } + else { + if (ScreenSaverTime) { + rep.state = ScreenSaverOff; + if (ScreenSaverTime < lastInput) + rep.tilOrSince = 0; + else + rep.tilOrSince = ScreenSaverTime - lastInput; + } + else { + rep.state = ScreenSaverDisabled; + rep.tilOrSince = 0; + } + } + rep.idle = lastInput; + rep.eventMask = getEventMask(pDraw->pScreen, client); + if (pPriv && pPriv->attr) + rep.kind = ScreenSaverExternal; + else if (ScreenSaverBlanking != DontPreferBlanking) + rep.kind = ScreenSaverBlanked; + else + rep.kind = ScreenSaverInternal; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.window); + swapl(&rep.tilOrSince); + swapl(&rep.idle); + swapl(&rep.eventMask); + } + WriteToClient(client, sizeof(xScreenSaverQueryInfoReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcScreenSaverSelectInput(client) +ClientPtr client; +{ + REQUEST(xScreenSaverSelectInputReq); + DrawablePtr pDraw; + + REQUEST_SIZE_MATCH(xScreenSaverSelectInputReq); + pDraw = (DrawablePtr) LookupDrawable(stuff->drawable, client); + if (!pDraw) + return BadDrawable; + if (!setEventMask(pDraw->pScreen, client, stuff->eventMask)) + return BadAlloc; + return Success; +} + +static int +ScreenSaverSetAttributes(ClientPtr client) +{ + REQUEST(xScreenSaverSetAttributesReq); + DrawablePtr pDraw; + + WindowPtr pParent; + + ScreenPtr pScreen; + + ScreenSaverScreenPrivatePtr pPriv = 0; + + ScreenSaverAttrPtr pAttr = 0; + + int ret; + + int len; + + int class, bw, depth; + + unsigned long visual; + + int idepth, ivisual; + + Bool fOK; + + DepthPtr pDepth; + + WindowOptPtr ancwopt; + + unsigned int *pVlist; + + unsigned long *values = 0; + + unsigned long tmask, imask; + + unsigned long val; + + Pixmap pixID; + + PixmapPtr pPixmap; + + Cursor cursorID; + + CursorPtr pCursor; + + Colormap cmap; + + ColormapPtr pCmap; + + REQUEST_AT_LEAST_SIZE(xScreenSaverSetAttributesReq); + pDraw = (DrawablePtr) LookupDrawable(stuff->drawable, client); + if (!pDraw) + return BadDrawable; + pScreen = pDraw->pScreen; + pParent = WindowTable[pScreen->myNum]; + + len = stuff->length - (sizeof(xScreenSaverSetAttributesReq) >> 2); + if (Ones(stuff->mask) != len) + return BadLength; + if (!stuff->width || !stuff->height) { + client->errorValue = 0; + return BadValue; + } + switch (class = stuff->c_class) { + case CopyFromParent: + case InputOnly: + case InputOutput: + break; + default: + client->errorValue = class; + return BadValue; + } + bw = stuff->borderWidth; + depth = stuff->depth; + visual = stuff->visualID; + + /* copied directly from CreateWindow */ + + if (class == CopyFromParent) + class = pParent->drawable.class; + + if ((class != InputOutput) && (class != InputOnly)) { + client->errorValue = class; + return BadValue; + } + + if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) + return BadMatch; + + if ((class == InputOnly) && ((bw != 0) || (depth != 0))) + return BadMatch; + + if ((class == InputOutput) && (depth == 0)) + depth = pParent->drawable.depth; + ancwopt = pParent->optional; + if (!ancwopt) + ancwopt = FindWindowWithOptional(pParent)->optional; + if (visual == CopyFromParent) + visual = ancwopt->visual; + + /* Find out if the depth and visual are acceptable for this Screen */ + if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth)) { + fOK = FALSE; + for (idepth = 0; idepth < pScreen->numDepths; idepth++) { + pDepth = (DepthPtr) & pScreen->allowedDepths[idepth]; + if ((depth == pDepth->depth) || (depth == 0)) { + for (ivisual = 0; ivisual < pDepth->numVids; ivisual++) { + if (visual == pDepth->vids[ivisual]) { + fOK = TRUE; + break; + } + } + } + } + if (fOK == FALSE) + return BadMatch; + } + + if (((stuff->mask & (CWBorderPixmap | CWBorderPixel)) == 0) && + (class != InputOnly) && (depth != pParent->drawable.depth)) { + return BadMatch; + } + + if (((stuff->mask & CWColormap) == 0) && + (class != InputOnly) && + ((visual != ancwopt->visual) || (ancwopt->colormap == None))) { + return BadMatch; + } + + /* end of errors from CreateWindow */ + + pPriv = GetScreenPrivate(pScreen); + if (pPriv && pPriv->attr) { + if (pPriv->attr->client != client) + return BadAccess; + } + if (!pPriv) { + pPriv = MakeScreenPrivate(pScreen); + if (!pPriv) + return FALSE; + } + pAttr = New(ScreenSaverAttrRec); + if (!pAttr) { + ret = BadAlloc; + goto bail; + } + /* over allocate for override redirect */ + values = malloc((len + 1) * sizeof(unsigned long)); + if (!values) { + ret = BadAlloc; + goto bail; + } + pAttr->screen = pScreen; + pAttr->client = client; + pAttr->x = stuff->x; + pAttr->y = stuff->y; + pAttr->width = stuff->width; + pAttr->height = stuff->height; + pAttr->borderWidth = stuff->borderWidth; + pAttr->class = stuff->c_class; + pAttr->depth = depth; + pAttr->visual = visual; + pAttr->colormap = None; + pAttr->pCursor = NullCursor; + pAttr->pBackgroundPixmap = NullPixmap; + pAttr->pBorderPixmap = NullPixmap; + pAttr->values = values; + /* + * go through the mask, checking the values, + * looking up pixmaps and cursors and hold a reference + * to them. + */ + pAttr->mask = tmask = stuff->mask | CWOverrideRedirect; + pVlist = (unsigned int *) (stuff + 1); + while (tmask) { + imask = lowbit(tmask); + tmask &= ~imask; + switch (imask) { + case CWBackPixmap: + pixID = (Pixmap) * pVlist; + if (pixID == None) { + *values++ = None; + } + else if (pixID == ParentRelative) { + if (depth != pParent->drawable.depth) { + ret = BadMatch; + goto PatchUp; + } + *values++ = ParentRelative; + } + else { + pPixmap = (PixmapPtr) LookupIDByType(pixID, RT_PIXMAP); + if (pPixmap != (PixmapPtr) NULL) { + if ((pPixmap->drawable.depth != depth) || + (pPixmap->drawable.pScreen != pScreen)) { + ret = BadMatch; + goto PatchUp; + } + pAttr->pBackgroundPixmap = pPixmap; + pPixmap->refcnt++; + pAttr->mask &= ~CWBackPixmap; + } + else { + ret = BadPixmap; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBackPixel: + *values++ = (CARD32) *pVlist; + break; + case CWBorderPixmap: + pixID = (Pixmap) * pVlist; + if (pixID == CopyFromParent) { + if (depth != pParent->drawable.depth) { + ret = BadMatch; + goto PatchUp; + } + *values++ = CopyFromParent; + } + else { + pPixmap = (PixmapPtr) LookupIDByType(pixID, RT_PIXMAP); + if (pPixmap) { + if ((pPixmap->drawable.depth != depth) || + (pPixmap->drawable.pScreen != pScreen)) { + ret = BadMatch; + goto PatchUp; + } + pAttr->pBorderPixmap = pPixmap; + pPixmap->refcnt++; + pAttr->mask &= ~CWBorderPixmap; + } + else { + ret = BadPixmap; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBorderPixel: + *values++ = (CARD32) *pVlist; + break; + case CWBitGravity: + val = (CARD8) *pVlist; + if (val > StaticGravity) { + ret = BadValue; + client->errorValue = val; + goto PatchUp; + } + *values++ = val; + break; + case CWWinGravity: + val = (CARD8) *pVlist; + if (val > StaticGravity) { + ret = BadValue; + client->errorValue = val; + goto PatchUp; + } + *values++ = val; + break; + case CWBackingStore: + val = (CARD8) *pVlist; + if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) { + ret = BadValue; + client->errorValue = val; + goto PatchUp; + } + *values++ = val; + break; + case CWBackingPlanes: + *values++ = (CARD32) *pVlist; + break; + case CWBackingPixel: + *values++ = (CARD32) *pVlist; + break; + case CWSaveUnder: + val = (BOOL) * pVlist; + if ((val != xTrue) && (val != xFalse)) { + ret = BadValue; + client->errorValue = val; + goto PatchUp; + } + *values++ = val; + break; + case CWEventMask: + *values++ = (CARD32) *pVlist; + break; + case CWDontPropagate: + *values++ = (CARD32) *pVlist; + break; + case CWOverrideRedirect: + if (!(stuff->mask & CWOverrideRedirect)) + pVlist--; + else { + val = (BOOL) * pVlist; + if ((val != xTrue) && (val != xFalse)) { + ret = BadValue; + client->errorValue = val; + goto PatchUp; + } + } + *values++ = xTrue; + break; + case CWColormap: + cmap = (Colormap) * pVlist; + pCmap = (ColormapPtr) LookupIDByType(cmap, RT_COLORMAP); + if (!pCmap) { + ret = BadColor; + client->errorValue = cmap; + goto PatchUp; + } + if (pCmap->pVisual->vid != visual || pCmap->pScreen != pScreen) { + ret = BadMatch; + goto PatchUp; + } + pAttr->colormap = cmap; + pAttr->mask &= ~CWColormap; + break; + case CWCursor: + cursorID = (Cursor) * pVlist; + if (cursorID == None) { + *values++ = None; + } + else { + pCursor = (CursorPtr) LookupIDByType(cursorID, RT_CURSOR); + if (!pCursor) { + ret = BadCursor; + client->errorValue = cursorID; + goto PatchUp; + } + pCursor->refcnt++; + pAttr->pCursor = pCursor; + pAttr->mask &= ~CWCursor; + } + break; + default: + ret = BadValue; + client->errorValue = stuff->mask; + goto PatchUp; + } + pVlist++; + } + if (pPriv->attr) + FreeScreenAttr(pPriv->attr); + pPriv->attr = pAttr; + pAttr->resource = FakeClientID(client->index); + if (!AddResource(pAttr->resource, AttrType, (pointer) pAttr)) + return BadAlloc; + return Success; + PatchUp: + FreeAttrs(pAttr); + bail: + CheckScreenPrivate(pScreen); + if (pAttr) + free(pAttr->values); + free(pAttr); + return ret; +} + +static int +ScreenSaverUnsetAttributes(ClientPtr client) +{ + REQUEST(xScreenSaverSetAttributesReq); + DrawablePtr pDraw; + + ScreenSaverScreenPrivatePtr pPriv; + + REQUEST_SIZE_MATCH(xScreenSaverUnsetAttributesReq); + pDraw = (DrawablePtr) LookupDrawable(stuff->drawable, client); + if (!pDraw) + return BadDrawable; + pPriv = GetScreenPrivate(pDraw->pScreen); + if (pPriv && pPriv->attr && pPriv->attr->client == client) { + FreeResource(pPriv->attr->resource, AttrType); + FreeScreenAttr(pPriv->attr); + pPriv->attr = NULL; + CheckScreenPrivate(pDraw->pScreen); + } + return Success; +} + +static int +ProcScreenSaverSetAttributes(ClientPtr client) +{ + + return ScreenSaverSetAttributes(client); +} + +static int +ProcScreenSaverUnsetAttributes(ClientPtr client) +{ + + return ScreenSaverUnsetAttributes(client); +} + +static int +ProcScreenSaverSuspend(ClientPtr client) +{ + ScreenSaverSuspensionPtr *prev, this; + + REQUEST(xScreenSaverSuspendReq); + REQUEST_SIZE_MATCH(xScreenSaverSuspendReq); + + /* Check if this client is suspending the screensaver */ + for (prev = &suspendingClients; (this = *prev); prev = &this->next) + if (this->pClient == client) + break; + + if (this) { + if (stuff->suspend == TRUE) + this->count++; + else if (--this->count == 0) + FreeResource(this->clientResource, RT_NONE); + + return Success; + } + + /* If we get to this point, this client isn't suspending the screensaver */ + if (stuff->suspend == FALSE) + return Success; + + /* + * Allocate a suspension record for the client, and stop the screensaver + * if it isn't already suspended by another client. We attach a resource ID + * to the record, so the screensaver will be reenabled and the record freed + * if the client disconnects without reenabling it first. + */ + this = malloc(sizeof(ScreenSaverSuspensionRec)); + + if (!this) + return BadAlloc; + + this->next = NULL; + this->pClient = client; + this->count = 1; + this->clientResource = FakeClientID(client->index); + + if (!AddResource(this->clientResource, SuspendType, (pointer) this)) { + free(this); + return BadAlloc; + } + + *prev = this; + if (!screenSaverSuspended) { + screenSaverSuspended = TRUE; + FreeScreenSaverTimer(); + } + + return (client->noClientException); +} + +static DISPATCH_PROC((*NormalVector[])) = { +ProcScreenSaverQueryVersion, + ProcScreenSaverQueryInfo, + ProcScreenSaverSelectInput, + ProcScreenSaverSetAttributes, + ProcScreenSaverUnsetAttributes, ProcScreenSaverSuspend,}; + +#define NUM_REQUESTS ((sizeof NormalVector) / (sizeof NormalVector[0])) + +static int +ProcScreenSaverDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + + if (stuff->data < NUM_REQUESTS) + return (*NormalVector[stuff->data]) (client); + return BadRequest; +} + +static int +SProcScreenSaverQueryVersion(client) +ClientPtr client; +{ + REQUEST(xScreenSaverQueryVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xScreenSaverQueryVersionReq); + return ProcScreenSaverQueryVersion(client); +} + +static int +SProcScreenSaverQueryInfo(client) +ClientPtr client; +{ + REQUEST(xScreenSaverQueryInfoReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xScreenSaverQueryInfoReq); + swapl(&stuff->drawable); + return ProcScreenSaverQueryInfo(client); +} + +static int +SProcScreenSaverSelectInput(client) +ClientPtr client; +{ + REQUEST(xScreenSaverSelectInputReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xScreenSaverSelectInputReq); + swapl(&stuff->drawable); + swapl(&stuff->eventMask); + return ProcScreenSaverSelectInput(client); +} + +static int +SProcScreenSaverSetAttributes(client) +ClientPtr client; +{ + REQUEST(xScreenSaverSetAttributesReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xScreenSaverSetAttributesReq); + swapl(&stuff->drawable); + swaps(&stuff->x); + swaps(&stuff->y); + swaps(&stuff->width); + swaps(&stuff->height); + swaps(&stuff->borderWidth); + swapl(&stuff->visualID); + swapl(&stuff->mask); + SwapRestL(stuff); + return ProcScreenSaverSetAttributes(client); +} + +static int +SProcScreenSaverUnsetAttributes(client) +ClientPtr client; +{ + REQUEST(xScreenSaverUnsetAttributesReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xScreenSaverUnsetAttributesReq); + swapl(&stuff->drawable); + return ProcScreenSaverUnsetAttributes(client); +} + +static int +SProcScreenSaverSuspend(ClientPtr client) +{ + REQUEST(xScreenSaverSuspendReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xScreenSaverSuspendReq); + return ProcScreenSaverSuspend(client); +} + +static DISPATCH_PROC((*SwappedVector[])) = { +SProcScreenSaverQueryVersion, + SProcScreenSaverQueryInfo, + SProcScreenSaverSelectInput, + SProcScreenSaverSetAttributes, + SProcScreenSaverUnsetAttributes, SProcScreenSaverSuspend,}; + +static int +SProcScreenSaverDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + + if (stuff->data < NUM_REQUESTS) + return (*SwappedVector[stuff->data]) (client); + return BadRequest; +} diff --git a/Xext/shape.c b/Xext/shape.c new file mode 100644 index 0000000..af2aab5 --- /dev/null +++ b/Xext/shape.c @@ -0,0 +1,1241 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include +#include +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" +#define _SHAPE_SERVER_ /* don't want Xlib structures */ +#include +#include "regionstr.h" +#include "gcstruct.h" +#include "extinit.h" + +typedef RegionPtr (*CreateDftPtr) (WindowPtr /* pWin */ + ); + +static int ShapeFreeClient(pointer /* data */ , + XID /* id */ + ); + +static int ShapeFreeEvents(pointer /* data */ , + XID /* id */ + ); + +static void ShapeResetProc(ExtensionEntry * /* extEntry */ + ); + +static void SShapeNotifyEvent(xShapeNotifyEvent * /* from */ , + xShapeNotifyEvent * /* to */ + ); + +static int + RegionOperate(ClientPtr /* client */ , + WindowPtr /* pWin */ , + int /* kind */ , + RegionPtr * /* destRgnp */ , + RegionPtr /* srcRgn */ , + int /* op */ , + int /* xoff */ , + int /* yoff */ , + CreateDftPtr /* create */ + ); + +/* SendShapeNotify, CreateBoundingShape and CreateClipShape are used + * externally by the Xfixes extension and are now defined in window.h + */ + +static DISPATCH_PROC(ProcShapeCombine); + +static DISPATCH_PROC(ProcShapeDispatch); + +static DISPATCH_PROC(ProcShapeGetRectangles); + +static DISPATCH_PROC(ProcShapeInputSelected); + +static DISPATCH_PROC(ProcShapeMask); + +static DISPATCH_PROC(ProcShapeOffset); + +static DISPATCH_PROC(ProcShapeQueryExtents); + +static DISPATCH_PROC(ProcShapeQueryVersion); + +static DISPATCH_PROC(ProcShapeRectangles); + +static DISPATCH_PROC(ProcShapeSelectInput); + +static DISPATCH_PROC(SProcShapeCombine); + +static DISPATCH_PROC(SProcShapeDispatch); + +static DISPATCH_PROC(SProcShapeGetRectangles); + +static DISPATCH_PROC(SProcShapeInputSelected); + +static DISPATCH_PROC(SProcShapeMask); + +static DISPATCH_PROC(SProcShapeOffset); + +static DISPATCH_PROC(SProcShapeQueryExtents); + +static DISPATCH_PROC(SProcShapeQueryVersion); + +static DISPATCH_PROC(SProcShapeRectangles); + +static DISPATCH_PROC(SProcShapeSelectInput); + + +#if 0 +static unsigned char ShapeReqCode = 0; +#endif +static int ShapeEventBase = 0; + +static RESTYPE ClientType, EventType; /* resource types for event masks */ + +/* + * each window has a list of clients requesting + * ShapeNotify events. Each client has a resource + * for each window it selects ShapeNotify input for, + * this resource is used to delete the ShapeNotifyRec + * entry from the per-window queue. + */ + +typedef struct _ShapeEvent *ShapeEventPtr; + +typedef struct _ShapeEvent { + ShapeEventPtr next; + ClientPtr client; + WindowPtr window; + XID clientResource; +} ShapeEventRec; + +/**************** + * ShapeExtensionInit + * + * Called from InitExtensions in main() or from QueryExtension() if the + * extension is dynamically loaded. + * + ****************/ + +void +ShapeExtensionInit(void) +{ + ExtensionEntry *extEntry; + + ClientType = CreateNewResourceType(ShapeFreeClient); + EventType = CreateNewResourceType(ShapeFreeEvents); + if (ClientType && EventType && + (extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0, + ProcShapeDispatch, SProcShapeDispatch, + ShapeResetProc, StandardMinorOpcode))) { +#if 0 + ShapeReqCode = (unsigned char) extEntry->base; +#endif + ShapeEventBase = extEntry->eventBase; + EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent; + } +} + + /*ARGSUSED*/ static void +ShapeResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static int +RegionOperate(client, pWin, kind, destRgnp, srcRgn, op, xoff, yoff, create) +ClientPtr client; + +WindowPtr pWin; + +int kind; + +RegionPtr *destRgnp, srcRgn; + +int op; + +int xoff, yoff; + +CreateDftPtr create; /* creates a reasonable *destRgnp */ +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (srcRgn && (xoff || yoff)) + REGION_TRANSLATE(srcRgn, xoff, yoff); + if (!pWin->parent) { + if (srcRgn) + REGION_DESTROY(srcRgn); + return Success; + } + + /* May/30/2001: + * The shape.PS specs say if src is None, existing shape is to be + * removed (and so the op-code has no meaning in such removal); + * see shape.PS, page 3, ShapeMask. + */ + if (srcRgn == NULL) { + if (*destRgnp != NULL) { + REGION_DESTROY(*destRgnp); + *destRgnp = 0; + /* go on to remove shape and generate ShapeNotify */ + } + else { + /* May/30/2001: + * The target currently has no shape in effect, so nothing to + * do here. The specs say that ShapeNotify is generated whenever + * the client region is "modified"; since no modification is done + * here, we do not generate that event. The specs does not say + * "it is an error to request removal when there is no shape in + * effect", so we return good status. + */ + return Success; + } + } + else + switch (op) { + case ShapeSet: + if (*destRgnp) + REGION_DESTROY(*destRgnp); + *destRgnp = srcRgn; + srcRgn = 0; + break; + case ShapeUnion: + if (*destRgnp) + REGION_UNION(*destRgnp, *destRgnp, srcRgn); + break; + case ShapeIntersect: + if (*destRgnp) + REGION_INTERSECT(*destRgnp, *destRgnp, srcRgn); + else { + *destRgnp = srcRgn; + srcRgn = 0; + } + break; + case ShapeSubtract: + if (!*destRgnp) + *destRgnp = (*create) (pWin); + REGION_SUBTRACT(*destRgnp, *destRgnp, srcRgn); + break; + case ShapeInvert: + if (!*destRgnp) + *destRgnp = REGION_CREATE((BoxPtr) 0, 0); + else + REGION_SUBTRACT(*destRgnp, srcRgn, *destRgnp); + break; + default: + client->errorValue = op; + return BadValue; + } + if (srcRgn) + REGION_DESTROY(srcRgn); + (*pScreen->SetShape) (pWin); + SendShapeNotify(pWin, kind); + return Success; +} + +RegionPtr +CreateBoundingShape(pWin) +WindowPtr pWin; +{ + BoxRec extents; + + extents.x1 = -wBorderWidth(pWin); + extents.y1 = -wBorderWidth(pWin); + extents.x2 = pWin->drawable.width + wBorderWidth(pWin); + extents.y2 = pWin->drawable.height + wBorderWidth(pWin); + return REGION_CREATE(&extents, 1); +} + +RegionPtr +CreateClipShape(pWin) +WindowPtr pWin; +{ + BoxRec extents; + + extents.x1 = 0; + extents.y1 = 0; + extents.x2 = pWin->drawable.width; + extents.y2 = pWin->drawable.height; + return REGION_CREATE(&extents, 1); +} + +static int +ProcShapeQueryVersion(client) +ClientPtr client; +{ + xShapeQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xShapeQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SHAPE_MAJOR_VERSION; + rep.minorVersion = SHAPE_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + } + WriteToClient(client, sizeof(xShapeQueryVersionReply), (char *) &rep); + return (client->noClientException); +} + +/***************** + * ProcShapeRectangles + * + *****************/ + +static int +ProcShapeRectangles(client) +ClientPtr client; +{ + WindowPtr pWin; + + REQUEST(xShapeRectanglesReq); + xRectangle *prects; + + int nrects, ctype; + + RegionPtr srcRgn; + + RegionPtr *destRgn; + + CreateDftPtr createDefault; + + REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq); + UpdateCurrentTime(); + pWin = LookupWindow(stuff->dest, client); + if (!pWin) + return BadWindow; + switch (stuff->destKind) { + case ShapeBounding: + createDefault = CreateBoundingShape; + break; + case ShapeClip: + createDefault = CreateClipShape; + break; + case ShapeInput: + createDefault = CreateBoundingShape; + break; + default: + client->errorValue = stuff->destKind; + return BadValue; + } + if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) && + (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) { + client->errorValue = stuff->ordering; + return BadValue; + } + nrects = ((stuff->length << 2) - sizeof(xShapeRectanglesReq)); + if (nrects & 4) + return BadLength; + nrects >>= 3; + prects = (xRectangle *) &stuff[1]; + ctype = VerifyRectOrder(nrects, prects, (int) stuff->ordering); + if (ctype < 0) + return BadMatch; + srcRgn = RECTS_TO_REGION(nrects, prects, ctype); + + if (!pWin->optional) + MakeWindowOptional(pWin); + switch (stuff->destKind) { + case ShapeBounding: + destRgn = &pWin->optional->boundingShape; + break; + case ShapeClip: + destRgn = &pWin->optional->clipShape; + break; + case ShapeInput: + destRgn = &pWin->optional->inputShape; + break; + default: + return BadValue; + } + + return RegionOperate(client, pWin, (int) stuff->destKind, + destRgn, srcRgn, (int) stuff->op, + stuff->xOff, stuff->yOff, createDefault); +} + + +/************** + * ProcShapeMask + **************/ + +static int +ProcShapeMask(client) +ClientPtr client; +{ + WindowPtr pWin; + + ScreenPtr pScreen; + + REQUEST(xShapeMaskReq); + RegionPtr srcRgn; + + RegionPtr *destRgn; + + PixmapPtr pPixmap; + + CreateDftPtr createDefault; + + REQUEST_SIZE_MATCH(xShapeMaskReq); + UpdateCurrentTime(); + pWin = SecurityLookupWindow(stuff->dest, client, SecurityWriteAccess); + if (!pWin) + return BadWindow; + switch (stuff->destKind) { + case ShapeBounding: + createDefault = CreateBoundingShape; + break; + case ShapeClip: + createDefault = CreateClipShape; + break; + case ShapeInput: + createDefault = CreateBoundingShape; + break; + default: + client->errorValue = stuff->destKind; + return BadValue; + } + pScreen = pWin->drawable.pScreen; + if (stuff->src == None) + srcRgn = 0; + else { + pPixmap = (PixmapPtr) SecurityLookupIDByType(client, stuff->src, + RT_PIXMAP, + SecurityReadAccess); + if (!pPixmap) + return BadPixmap; + if (pPixmap->drawable.pScreen != pScreen || + pPixmap->drawable.depth != 1) + return BadMatch; + srcRgn = BITMAP_TO_REGION(pScreen, pPixmap); + if (!srcRgn) + return BadAlloc; + } + + if (!pWin->optional) + MakeWindowOptional(pWin); + switch (stuff->destKind) { + case ShapeBounding: + destRgn = &pWin->optional->boundingShape; + break; + case ShapeClip: + destRgn = &pWin->optional->clipShape; + break; + case ShapeInput: + destRgn = &pWin->optional->inputShape; + break; + default: + return BadValue; + } + + return RegionOperate(client, pWin, (int) stuff->destKind, + destRgn, srcRgn, (int) stuff->op, + stuff->xOff, stuff->yOff, createDefault); +} + + +/************ + * ProcShapeCombine + ************/ + +static int +ProcShapeCombine(client) +ClientPtr client; +{ + WindowPtr pSrcWin, pDestWin; + + ScreenPtr pScreen; + + REQUEST(xShapeCombineReq); + RegionPtr srcRgn; + + RegionPtr *destRgn; + + CreateDftPtr createDefault; + + CreateDftPtr createSrc; + + RegionPtr tmp; + + REQUEST_SIZE_MATCH(xShapeCombineReq); + UpdateCurrentTime(); + pDestWin = LookupWindow(stuff->dest, client); + if (!pDestWin) + return BadWindow; + if (!pDestWin->optional) + MakeWindowOptional(pDestWin); + switch (stuff->destKind) { + case ShapeBounding: + createDefault = CreateBoundingShape; + break; + case ShapeClip: + createDefault = CreateClipShape; + break; + case ShapeInput: + createDefault = CreateBoundingShape; + break; + default: + client->errorValue = stuff->destKind; + return BadValue; + } + pScreen = pDestWin->drawable.pScreen; + + pSrcWin = LookupWindow(stuff->src, client); + if (!pSrcWin) + return BadWindow; + switch (stuff->srcKind) { + case ShapeBounding: + srcRgn = wBoundingShape(pSrcWin); + createSrc = CreateBoundingShape; + break; + case ShapeClip: + srcRgn = wClipShape(pSrcWin); + createSrc = CreateClipShape; + break; + case ShapeInput: + srcRgn = wInputShape(pSrcWin); + createSrc = CreateBoundingShape; + break; + default: + client->errorValue = stuff->srcKind; + return BadValue; + } + if (pSrcWin->drawable.pScreen != pScreen) { + return BadMatch; + } + + if (srcRgn) { + tmp = REGION_CREATE((BoxPtr) 0, 0); + REGION_COPY(tmp, srcRgn); + srcRgn = tmp; + } + else + srcRgn = (*createSrc) (pSrcWin); + + if (!pDestWin->optional) + MakeWindowOptional(pDestWin); + switch (stuff->destKind) { + case ShapeBounding: + destRgn = &pDestWin->optional->boundingShape; + break; + case ShapeClip: + destRgn = &pDestWin->optional->clipShape; + break; + case ShapeInput: + destRgn = &pDestWin->optional->inputShape; + break; + default: + return BadValue; + } + + return RegionOperate(client, pDestWin, (int) stuff->destKind, + destRgn, srcRgn, (int) stuff->op, + stuff->xOff, stuff->yOff, createDefault); +} + + +/************* + * ProcShapeOffset + *************/ + +static int +ProcShapeOffset(client) +ClientPtr client; +{ + WindowPtr pWin; + + ScreenPtr pScreen; + + REQUEST(xShapeOffsetReq); + RegionPtr srcRgn; + + REQUEST_SIZE_MATCH(xShapeOffsetReq); + UpdateCurrentTime(); + pWin = LookupWindow(stuff->dest, client); + if (!pWin) + return BadWindow; + switch (stuff->destKind) { + case ShapeBounding: + srcRgn = wBoundingShape(pWin); + break; + case ShapeClip: + srcRgn = wClipShape(pWin); + break; + case ShapeInput: + srcRgn = wInputShape(pWin); + break; + default: + client->errorValue = stuff->destKind; + return BadValue; + } + pScreen = pWin->drawable.pScreen; + if (srcRgn) { + REGION_TRANSLATE(srcRgn, stuff->xOff, stuff->yOff); + (*pScreen->SetShape) (pWin); + } + SendShapeNotify(pWin, (int) stuff->destKind); + return Success; +} + + +static int +ProcShapeQueryExtents(client) +ClientPtr client; +{ + REQUEST(xShapeQueryExtentsReq); + WindowPtr pWin; + + xShapeQueryExtentsReply rep; + + BoxRec extents, *pExtents; + + RegionPtr region; + + REQUEST_SIZE_MATCH(xShapeQueryExtentsReq); + pWin = LookupWindow(stuff->window, client); + if (!pWin) + return BadWindow; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.boundingShaped = (wBoundingShape(pWin) != 0); + rep.clipShaped = (wClipShape(pWin) != 0); + if ((region = wBoundingShape(pWin))) { + /* this is done in two steps because of a compiler bug on SunOS 4.1.3 */ + pExtents = REGION_EXTENTS(region); + extents = *pExtents; + } + else { + extents.x1 = -wBorderWidth(pWin); + extents.y1 = -wBorderWidth(pWin); + extents.x2 = pWin->drawable.width + wBorderWidth(pWin); + extents.y2 = pWin->drawable.height + wBorderWidth(pWin); + } + rep.xBoundingShape = extents.x1; + rep.yBoundingShape = extents.y1; + rep.widthBoundingShape = extents.x2 - extents.x1; + rep.heightBoundingShape = extents.y2 - extents.y1; + if ((region = wClipShape(pWin))) { + /* this is done in two steps because of a compiler bug on SunOS 4.1.3 */ + pExtents = REGION_EXTENTS(region); + extents = *pExtents; + } + else { + extents.x1 = 0; + extents.y1 = 0; + extents.x2 = pWin->drawable.width; + extents.y2 = pWin->drawable.height; + } + rep.xClipShape = extents.x1; + rep.yClipShape = extents.y1; + rep.widthClipShape = extents.x2 - extents.x1; + rep.heightClipShape = extents.y2 - extents.y1; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.xBoundingShape); + swaps(&rep.yBoundingShape); + swaps(&rep.widthBoundingShape); + swaps(&rep.heightBoundingShape); + swaps(&rep.xClipShape); + swaps(&rep.yClipShape); + swaps(&rep.widthClipShape); + swaps(&rep.heightClipShape); + } + WriteToClient(client, sizeof(xShapeQueryExtentsReply), (char *) &rep); + return (client->noClientException); +} + + /*ARGSUSED*/ static int +ShapeFreeClient(data, id) +pointer data; + +XID id; +{ + ShapeEventPtr pShapeEvent; + + WindowPtr pWin; + + ShapeEventPtr *pHead, pCur, pPrev; + + pShapeEvent = (ShapeEventPtr) data; + pWin = pShapeEvent->window; + pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType); + if (pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pShapeEvent; pCur = pCur->next) + pPrev = pCur; + if (pCur) { + if (pPrev) + pPrev->next = pShapeEvent->next; + else + *pHead = pShapeEvent->next; + } + } + free((pointer) pShapeEvent); + return 1; +} + + /*ARGSUSED*/ static int +ShapeFreeEvents(data, id) +pointer data; + +XID id; +{ + ShapeEventPtr *pHead, pCur, pNext; + + pHead = (ShapeEventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource(pCur->clientResource, ClientType); + free((pointer) pCur); + } + free((pointer) pHead); + return 1; +} + +static int +ProcShapeSelectInput(client) +ClientPtr client; +{ + REQUEST(xShapeSelectInputReq); + WindowPtr pWin; + + ShapeEventPtr pShapeEvent, pNewShapeEvent, *pHead; + + XID clientResource; + + REQUEST_SIZE_MATCH(xShapeSelectInputReq); + pWin = SecurityLookupWindow(stuff->window, client, SecurityWriteAccess); + if (!pWin) + return BadWindow; + pHead = (ShapeEventPtr *) SecurityLookupIDByType(client, + pWin->drawable.id, + EventType, + SecurityWriteAccess); + switch (stuff->enable) { + case xTrue: + if (pHead) { + + /* check for existing entry. */ + for (pShapeEvent = *pHead; + pShapeEvent; pShapeEvent = pShapeEvent->next) { + if (pShapeEvent->client == client) + return Success; + } + } + + /* build the entry */ + pNewShapeEvent = (ShapeEventPtr) + malloc(sizeof(ShapeEventRec)); + if (!pNewShapeEvent) + return BadAlloc; + pNewShapeEvent->next = 0; + pNewShapeEvent->client = client; + pNewShapeEvent->window = pWin; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID(client->index); + pNewShapeEvent->clientResource = clientResource; + if (!AddResource(clientResource, ClientType, (pointer) pNewShapeEvent)) + return BadAlloc; + /* + * create a resource to contain a pointer to the list + * of clients selecting input. This must be indirect as + * the list may be arbitrarily rearranged which cannot be + * done through the resource database. + */ + if (!pHead) { + pHead = malloc(sizeof(ShapeEventPtr)); + if (!pHead || + !AddResource(pWin->drawable.id, EventType, (pointer) pHead)) { + FreeResource(clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pNewShapeEvent->next = *pHead; + *pHead = pNewShapeEvent; + break; + case xFalse: + /* delete the interest */ + if (pHead) { + pNewShapeEvent = 0; + for (pShapeEvent = *pHead; pShapeEvent; + pShapeEvent = pShapeEvent->next) { + if (pShapeEvent->client == client) + break; + pNewShapeEvent = pShapeEvent; + } + if (pShapeEvent) { + FreeResource(pShapeEvent->clientResource, ClientType); + if (pNewShapeEvent) + pNewShapeEvent->next = pShapeEvent->next; + else + *pHead = pShapeEvent->next; + free(pShapeEvent); + } + } + break; + default: + client->errorValue = stuff->enable; + return BadValue; + } + return Success; +} + +/* + * deliver the event + */ + +void +SendShapeNotify(pWin, which) +WindowPtr pWin; + +int which; +{ + ShapeEventPtr *pHead, pShapeEvent; + + ClientPtr client; + + xShapeNotifyEvent se; + + BoxRec extents; + + RegionPtr region; + + BYTE shaped; + + pHead = (ShapeEventPtr *) LookupIDByType(pWin->drawable.id, EventType); + if (!pHead) + return; + switch (which) { + case ShapeBounding: + region = wBoundingShape(pWin); + if (region) { + extents = *REGION_EXTENTS(region); + shaped = xTrue; + } + else { + extents.x1 = -wBorderWidth(pWin); + extents.y1 = -wBorderWidth(pWin); + extents.x2 = pWin->drawable.width + wBorderWidth(pWin); + extents.y2 = pWin->drawable.height + wBorderWidth(pWin); + shaped = xFalse; + } + break; + case ShapeClip: + region = wClipShape(pWin); + if (region) { + extents = *REGION_EXTENTS(region); + shaped = xTrue; + } + else { + extents.x1 = 0; + extents.y1 = 0; + extents.x2 = pWin->drawable.width; + extents.y2 = pWin->drawable.height; + shaped = xFalse; + } + break; + case ShapeInput: + region = wInputShape(pWin); + if (region) { + extents = *REGION_EXTENTS(region); + shaped = xTrue; + } + else { + extents.x1 = -wBorderWidth(pWin); + extents.y1 = -wBorderWidth(pWin); + extents.x2 = pWin->drawable.width + wBorderWidth(pWin); + extents.y2 = pWin->drawable.height + wBorderWidth(pWin); + shaped = xFalse; + } + break; + default: + return; + } + for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) { + client = pShapeEvent->client; + if (client == serverClient || client->clientGone) + continue; + se.type = ShapeNotify + ShapeEventBase; + se.kind = which; + se.window = pWin->drawable.id; + se.sequenceNumber = client->sequence; + se.x = extents.x1; + se.y = extents.y1; + se.width = extents.x2 - extents.x1; + se.height = extents.y2 - extents.y1; + se.time = currentTime.milliseconds; + se.shaped = shaped; + WriteEventsToClient(client, 1, (xEvent *) &se); + } +} + +static int +ProcShapeInputSelected(client) +ClientPtr client; +{ + REQUEST(xShapeInputSelectedReq); + WindowPtr pWin; + + ShapeEventPtr pShapeEvent, *pHead; + + int enabled; + + xShapeInputSelectedReply rep; + + REQUEST_SIZE_MATCH(xShapeInputSelectedReq); + pWin = LookupWindow(stuff->window, client); + if (!pWin) + return BadWindow; + pHead = (ShapeEventPtr *) SecurityLookupIDByType(client, + pWin->drawable.id, + EventType, + SecurityReadAccess); + enabled = xFalse; + if (pHead) { + for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) { + if (pShapeEvent->client == client) { + enabled = xTrue; + break; + } + } + } + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.enabled = enabled; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + WriteToClient(client, sizeof(xShapeInputSelectedReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcShapeGetRectangles(client) +ClientPtr client; +{ + REQUEST(xShapeGetRectanglesReq); + WindowPtr pWin; + + xShapeGetRectanglesReply rep; + + xRectangle *rects; + + int nrects, i; + + RegionPtr region; + + REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); + pWin = LookupWindow(stuff->window, client); + if (!pWin) + return BadWindow; + switch (stuff->kind) { + case ShapeBounding: + region = wBoundingShape(pWin); + break; + case ShapeClip: + region = wClipShape(pWin); + break; + case ShapeInput: + region = wInputShape(pWin); + break; + default: + client->errorValue = stuff->kind; + return BadValue; + } + if (!region) { + nrects = 1; + rects = (xRectangle *) ALLOCATE_LOCAL(sizeof(xRectangle)); + if (!rects) + return BadAlloc; + switch (stuff->kind) { + case ShapeBounding: + rects->x = -(int) wBorderWidth(pWin); + rects->y = -(int) wBorderWidth(pWin); + rects->width = pWin->drawable.width + wBorderWidth(pWin); + rects->height = pWin->drawable.height + wBorderWidth(pWin); + break; + case ShapeClip: + rects->x = 0; + rects->y = 0; + rects->width = pWin->drawable.width; + rects->height = pWin->drawable.height; + break; + case ShapeInput: + rects->x = -(int) wBorderWidth(pWin); + rects->y = -(int) wBorderWidth(pWin); + rects->width = pWin->drawable.width + wBorderWidth(pWin); + rects->height = pWin->drawable.height + wBorderWidth(pWin); + break; + } + } + else { + BoxPtr box; + + nrects = REGION_NUM_RECTS(region); + box = REGION_RECTS(region); + rects = (xRectangle *) ALLOCATE_LOCAL(nrects * sizeof(xRectangle)); + if (!rects && nrects) + return BadAlloc; + for (i = 0; i < nrects; i++, box++) { + rects[i].x = box->x1; + rects[i].y = box->y1; + rects[i].width = box->x2 - box->x1; + rects[i].height = box->y2 - box->y1; + } + } + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = (nrects * sizeof(xRectangle)) >> 2; + rep.ordering = YXBanded; + rep.nrects = nrects; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.nrects); + SwapShorts((short *) rects, (unsigned long) nrects * 4); + } + WriteToClient(client, sizeof(rep), (char *) &rep); + WriteToClient(client, nrects * sizeof(xRectangle), (char *) rects); + DEALLOCATE_LOCAL(rects); + return client->noClientException; +} + +static int +ProcShapeDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_ShapeQueryVersion: + return ProcShapeQueryVersion(client); + case X_ShapeRectangles: + return ProcShapeRectangles(client); + case X_ShapeMask: + return ProcShapeMask(client); + case X_ShapeCombine: + return ProcShapeCombine(client); + case X_ShapeOffset: + return ProcShapeOffset(client); + case X_ShapeQueryExtents: + return ProcShapeQueryExtents(client); + case X_ShapeSelectInput: + return ProcShapeSelectInput(client); + case X_ShapeInputSelected: + return ProcShapeInputSelected(client); + case X_ShapeGetRectangles: + return ProcShapeGetRectangles(client); + default: + return BadRequest; + } +} + +static void +SShapeNotifyEvent(from, to) +xShapeNotifyEvent *from, *to; +{ + to->type = from->type; + to->kind = from->kind; + cpswapl(from->window, to->window); + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswaps(from->x, to->x); + cpswaps(from->y, to->y); + cpswaps(from->width, to->width); + cpswaps(from->height, to->height); + cpswapl(from->time, to->time); + to->shaped = from->shaped; +} + +static int +SProcShapeQueryVersion(client) +ClientPtr client; +{ + REQUEST(xShapeQueryVersionReq); + + swaps(&stuff->length); + return ProcShapeQueryVersion(client); +} + +static int +SProcShapeRectangles(client) +ClientPtr client; +{ + REQUEST(xShapeRectanglesReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq); + swapl(&stuff->dest); + swaps(&stuff->xOff); + swaps(&stuff->yOff); + SwapRestS(stuff); + return ProcShapeRectangles(client); +} + +static int +SProcShapeMask(client) +ClientPtr client; +{ + REQUEST(xShapeMaskReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeMaskReq); + swapl(&stuff->dest); + swaps(&stuff->xOff); + swaps(&stuff->yOff); + swapl(&stuff->src); + return ProcShapeMask(client); +} + +static int +SProcShapeCombine(client) +ClientPtr client; +{ + REQUEST(xShapeCombineReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeCombineReq); + swapl(&stuff->dest); + swaps(&stuff->xOff); + swaps(&stuff->yOff); + swapl(&stuff->src); + return ProcShapeCombine(client); +} + +static int +SProcShapeOffset(client) +ClientPtr client; +{ + REQUEST(xShapeOffsetReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeOffsetReq); + swapl(&stuff->dest); + swaps(&stuff->xOff); + swaps(&stuff->yOff); + return ProcShapeOffset(client); +} + +static int +SProcShapeQueryExtents(client) +ClientPtr client; +{ + REQUEST(xShapeQueryExtentsReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeQueryExtentsReq); + swapl(&stuff->window); + return ProcShapeQueryExtents(client); +} + +static int +SProcShapeSelectInput(client) +ClientPtr client; +{ + REQUEST(xShapeSelectInputReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeSelectInputReq); + swapl(&stuff->window); + return ProcShapeSelectInput(client); +} + +static int +SProcShapeInputSelected(client) +ClientPtr client; +{ + REQUEST(xShapeInputSelectedReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeInputSelectedReq); + swapl(&stuff->window); + return ProcShapeInputSelected(client); +} + +static int +SProcShapeGetRectangles(client) +ClientPtr client; +{ + REQUEST(xShapeGetRectanglesReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShapeGetRectanglesReq); + swapl(&stuff->window); + return ProcShapeGetRectangles(client); +} + +static int +SProcShapeDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_ShapeQueryVersion: + return SProcShapeQueryVersion(client); + case X_ShapeRectangles: + return SProcShapeRectangles(client); + case X_ShapeMask: + return SProcShapeMask(client); + case X_ShapeCombine: + return SProcShapeCombine(client); + case X_ShapeOffset: + return SProcShapeOffset(client); + case X_ShapeQueryExtents: + return SProcShapeQueryExtents(client); + case X_ShapeSelectInput: + return SProcShapeSelectInput(client); + case X_ShapeInputSelected: + return SProcShapeInputSelected(client); + case X_ShapeGetRectangles: + return SProcShapeGetRectangles(client); + default: + return BadRequest; + } +} diff --git a/Xext/shm.c b/Xext/shm.c new file mode 100644 index 0000000..edb9701 --- /dev/null +++ b/Xext/shm.c @@ -0,0 +1,991 @@ +/************************************************************ + +Copyright 1989, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +********************************************************/ + +/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ + +#define SHM + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "resource.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "extnsionst.h" +#include "servermd.h" +#define _XSHM_SERVER_ +#include +#include + + +#include "extinit.h" + +typedef struct _ShmDesc { + struct _ShmDesc *next; + int shmid; + int refcnt; + char *addr; + Bool writable; + unsigned long size; +} ShmDescRec, *ShmDescPtr; + +static void miShmPutImage(XSHM_PUT_IMAGE_ARGS); + +static void fbShmPutImage(XSHM_PUT_IMAGE_ARGS); + +static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); + +static int ShmDetachSegment(pointer /* value */ , + XID /* shmseg */ + ); + +static void ShmResetProc(ExtensionEntry * /* extEntry */ + ); + +static void SShmCompletionEvent(xShmCompletionEvent * /* from */ , + xShmCompletionEvent * /* to */ + ); + +static Bool ShmDestroyPixmap(PixmapPtr pPixmap); + +static DISPATCH_PROC(ProcShmAttach); + +static DISPATCH_PROC(ProcShmCreatePixmap); + +static DISPATCH_PROC(ProcShmDetach); + +static DISPATCH_PROC(ProcShmDispatch); + +static DISPATCH_PROC(ProcShmGetImage); + +static DISPATCH_PROC(ProcShmPutImage); + +static DISPATCH_PROC(ProcShmQueryVersion); + +static DISPATCH_PROC(SProcShmAttach); + +static DISPATCH_PROC(SProcShmCreatePixmap); + +static DISPATCH_PROC(SProcShmDetach); + +static DISPATCH_PROC(SProcShmDispatch); + +static DISPATCH_PROC(SProcShmGetImage); + +static DISPATCH_PROC(SProcShmPutImage); + +static DISPATCH_PROC(SProcShmQueryVersion); + +static unsigned char ShmReqCode; + +_X_EXPORT int ShmCompletionCode; + +_X_EXPORT int BadShmSegCode; + +_X_EXPORT RESTYPE ShmSegType; + +static ShmDescPtr Shmsegs; + +static Bool sharedPixmaps; + +static int pixmapFormat; + +static int shmPixFormat[MAXSCREENS]; + +static const ShmFuncs * shmFuncs[MAXSCREENS]; + +static DestroyPixmapProcPtr destroyPixmap[MAXSCREENS]; + +static int shmPixmapPrivate; +static const ShmFuncs miFuncs = { NULL, miShmPutImage }; +static const ShmFuncs fbFuncs = { fbShmCreatePixmap, fbShmPutImage }; + +#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ +{ \ + shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \ + if (!shmdesc) \ + { \ + client->errorValue = shmseg; \ + return BadShmSegCode; \ + } \ +} + +#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ +{ \ + VERIFY_SHMSEG(shmseg, shmdesc, client); \ + if ((offset & 3) || (offset > shmdesc->size)) \ + { \ + client->errorValue = offset; \ + return BadValue; \ + } \ + if (needwrite && !shmdesc->writable) \ + return BadAccess; \ +} + +#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ +{ \ + if ((offset + len) > shmdesc->size) \ + { \ + return BadAccess; \ + } \ +} + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) +#include + +static Bool badSysCall = FALSE; + +static void +SigSysHandler(signo) +int signo; +{ + badSysCall = TRUE; +} + +static Bool +CheckForShmSyscall() +{ + void (*oldHandler) (); + + int shmid = -1; + + /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ + oldHandler = signal(SIGSYS, SigSysHandler); + + badSysCall = FALSE; + shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); + + if (shmid != -1) { + /* Successful allocation - clean up */ + shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL); + } + else { + /* Allocation failed */ + badSysCall = TRUE; + } + signal(SIGSYS, oldHandler); + return (!badSysCall); +} + +#define MUST_CHECK_FOR_SHM_SYSCALL + +#endif + +void +ShmExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + + int i; + +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + if (!CheckForShmSyscall()) { + ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); + return; + } +#endif + + sharedPixmaps = xFalse; + pixmapFormat = 0; + { + sharedPixmaps = xTrue; + pixmapFormat = shmPixFormat[0]; + for (i = 0; i < screenInfo.numScreens; i++) { + if (!shmFuncs[i]) + shmFuncs[i] = &miFuncs; + if (!shmFuncs[i]->CreatePixmap) + sharedPixmaps = xFalse; + if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat)) { + sharedPixmaps = xFalse; + pixmapFormat = 0; + } + } + if (!pixmapFormat) + pixmapFormat = ZPixmap; + if (sharedPixmaps) { + for (i = 0; i < screenInfo.numScreens; i++) { + destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap; + screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; + } + shmPixmapPrivate = AllocatePixmapPrivateIndex(); + for (i = 0; i < screenInfo.numScreens; i++) { + if (!AllocatePixmapPrivate(screenInfo.screens[i], + shmPixmapPrivate, 0)) + return; + } + } + } + ShmSegType = CreateNewResourceType(ShmDetachSegment); + if (ShmSegType && + (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, + ProcShmDispatch, SProcShmDispatch, + ShmResetProc, StandardMinorOpcode))) { + ShmReqCode = (unsigned char) extEntry->base; + ShmCompletionCode = extEntry->eventBase; + BadShmSegCode = extEntry->errorBase; + EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; + } +} + + /*ARGSUSED*/ static void +ShmResetProc(extEntry) +ExtensionEntry *extEntry; +{ + int i; + + for (i = 0; i < MAXSCREENS; i++) { + shmFuncs[i] = (ShmFuncsPtr) NULL; + shmPixFormat[i] = 0; + } +} + +void +ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) +{ + shmFuncs[pScreen->myNum] = funcs; +} + +void +ShmSetPixmapFormat(ScreenPtr pScreen, int format) +{ + shmPixFormat[pScreen->myNum] = format; +} + +static Bool +ShmDestroyPixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + + Bool ret; + + if (pPixmap->refcnt == 1) { + ShmDescPtr shmdesc; + + shmdesc = (ShmDescPtr) pPixmap->devPrivates[shmPixmapPrivate].ptr; + if (shmdesc) + ShmDetachSegment((pointer) shmdesc, pPixmap->drawable.id); + } + + pScreen->DestroyPixmap = destroyPixmap[pScreen->myNum]; + ret = (*pScreen->DestroyPixmap) (pPixmap); + destroyPixmap[pScreen->myNum] = pScreen->DestroyPixmap; + pScreen->DestroyPixmap = ShmDestroyPixmap; + return ret; +} + +void +ShmRegisterFbFuncs(pScreen) +ScreenPtr pScreen; +{ + shmFuncs[pScreen->myNum] = &fbFuncs; +} + +static int +ProcShmQueryVersion(client) +ClientPtr client; +{ + xShmQueryVersionReply rep; + + + REQUEST_SIZE_MATCH(xShmQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.sharedPixmaps = sharedPixmaps; + rep.pixmapFormat = pixmapFormat; + rep.majorVersion = SHM_MAJOR_VERSION; + rep.minorVersion = SHM_MINOR_VERSION; + rep.uid = geteuid(); + rep.gid = getegid(); + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + swaps(&rep.uid); + swaps(&rep.gid); + } + WriteToClient(client, sizeof(xShmQueryVersionReply), (char *) &rep); + return (client->noClientException); +} + +/* + * Simulate the access() system call for a shared memory segement, + * using the credentials from the client if available + */ +static int +shm_access(ClientPtr client, struct ipc_perm *perm, int readonly) +{ + int uid, gid; + + mode_t mask; + + if (LocalClientCred(client, &uid, &gid) != -1) { + + /* User id 0 always gets access */ + if (uid == 0) { + return 0; + } + /* Check the owner */ + if (perm->uid == uid || perm->cuid == uid) { + mask = S_IRUSR; + if (!readonly) { + mask |= S_IWUSR; + } + return (perm->mode & mask) == mask ? 0 : -1; + } + /* Check the group */ + if (perm->gid == gid || perm->cgid == gid) { + mask = S_IRGRP; + if (!readonly) { + mask |= S_IWGRP; + } + return (perm->mode & mask) == mask ? 0 : -1; + } + } + /* Otherwise, check everyone else */ + mask = S_IROTH; + if (!readonly) { + mask |= S_IWOTH; + } + return (perm->mode & mask) == mask ? 0 : -1; +} + +static int +ProcShmAttach(client) +ClientPtr client; +{ + struct shmid_ds buf; + + ShmDescPtr shmdesc; + + REQUEST(xShmAttachReq); + + REQUEST_SIZE_MATCH(xShmAttachReq); + LEGAL_NEW_RESOURCE(stuff->shmseg, client); + if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) { + client->errorValue = stuff->readOnly; + return (BadValue); + } + for (shmdesc = Shmsegs; + shmdesc && (shmdesc->shmid != stuff->shmid); shmdesc = shmdesc->next); + if (shmdesc) { + if (!stuff->readOnly && !shmdesc->writable) + return BadAccess; + shmdesc->refcnt++; + } + else { + shmdesc = malloc(sizeof(ShmDescRec)); + if (!shmdesc) + return BadAlloc; + shmdesc->addr = shmat(stuff->shmid, 0, + stuff->readOnly ? SHM_RDONLY : 0); + if ((shmdesc->addr == ((char *) -1)) || + shmctl(stuff->shmid, IPC_STAT, &buf)) { + free(shmdesc); + return BadAccess; + } + + /* The attach was performed with root privs. We must + * do manual checking of access rights for the credentials + * of the client */ + + if (shm_access(client, &(buf.shm_perm), stuff->readOnly) == -1) { + shmdt(shmdesc->addr); + free(shmdesc); + return BadAccess; + } + + shmdesc->shmid = stuff->shmid; + shmdesc->refcnt = 1; + shmdesc->writable = !stuff->readOnly; + shmdesc->size = buf.shm_segsz; + shmdesc->next = Shmsegs; + Shmsegs = shmdesc; + } + if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc)) + return BadAlloc; + return (client->noClientException); +} + + /*ARGSUSED*/ static int +ShmDetachSegment(value, shmseg) +pointer value; /* must conform to DeleteType */ + +XID shmseg; +{ + ShmDescPtr shmdesc = (ShmDescPtr) value; + + ShmDescPtr *prev; + + if (--shmdesc->refcnt) + return TRUE; + shmdt(shmdesc->addr); + for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next); + *prev = shmdesc->next; + free(shmdesc); + return Success; +} + +static int +ProcShmDetach(client) +ClientPtr client; +{ + ShmDescPtr shmdesc; + + REQUEST(xShmDetachReq); + + REQUEST_SIZE_MATCH(xShmDetachReq); + VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); + FreeResource(stuff->shmseg, RT_NONE); + return (client->noClientException); +} + +static void +miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) +DrawablePtr dst; + +GCPtr pGC; + +int depth, w, h, sx, sy, sw, sh, dx, dy; + +unsigned int format; + +char *data; +{ + PixmapPtr pmap; + + GCPtr putGC; + + putGC = GetScratchGC(depth, dst->pScreen); + if (!putGC) + return; + pmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth); + if (!pmap) { + FreeScratchGC(putGC); + return; + } + ValidateGC((DrawablePtr) pmap, putGC); + (*putGC->ops->PutImage) ((DrawablePtr) pmap, putGC, depth, -sx, -sy, w, h, + 0, (format == XYPixmap) ? XYPixmap : ZPixmap, + data); + FreeScratchGC(putGC); + if (format == XYBitmap) + (void) (*pGC->ops->CopyPlane) ((DrawablePtr) pmap, dst, pGC, 0, 0, sw, + sh, dx, dy, 1L); + else + (void) (*pGC->ops->CopyArea) ((DrawablePtr) pmap, dst, pGC, 0, 0, sw, + sh, dx, dy); + (*pmap->drawable.pScreen->DestroyPixmap) (pmap); +} + +static void +fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) +DrawablePtr dst; + +GCPtr pGC; + +int depth, w, h, sx, sy, sw, sh, dx, dy; + +unsigned int format; + +char *data; +{ + if ((format == ZPixmap) || (depth == 1)) { + PixmapPtr pPixmap; + + pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, + BitsPerPixel(depth), PixmapBytePad(w, + depth), + (pointer) data); + if (!pPixmap) + return; + if (format == XYBitmap) + (void) (*pGC->ops->CopyPlane) ((DrawablePtr) pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy, 1L); + else + (void) (*pGC->ops->CopyArea) ((DrawablePtr) pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy); + FreeScratchPixmapHeader(pPixmap); + } + else + miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, + data); +} + + +static int +ProcShmPutImage(client) +ClientPtr client; +{ + GCPtr pGC; + + DrawablePtr pDraw; + + long length; + + ShmDescPtr shmdesc; + + REQUEST(xShmPutImageReq); + + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); + if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) + return BadValue; + if (stuff->format == XYBitmap) { + if (stuff->depth != 1) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + } + else if (stuff->format == XYPixmap) { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, stuff->depth); + } + else { + client->errorValue = stuff->format; + return BadValue; + } + + VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, client); + if (stuff->srcX > stuff->totalWidth) { + client->errorValue = stuff->srcX; + return BadValue; + } + if (stuff->srcY > stuff->totalHeight) { + client->errorValue = stuff->srcY; + return BadValue; + } + if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) { + client->errorValue = stuff->srcWidth; + return BadValue; + } + if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) { + client->errorValue = stuff->srcHeight; + return BadValue; + } + + if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || + ((stuff->format != ZPixmap) && + (stuff->srcX < screenInfo.bitmapScanlinePad) && + ((stuff->format == XYBitmap) || + ((stuff->srcY == 0) && + (stuff->srcHeight == stuff->totalHeight))))) && + ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) + (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, + stuff->dstX, stuff->dstY, + stuff->totalWidth, stuff->srcHeight, + stuff->srcX, stuff->format, + shmdesc->addr + stuff->offset + + (stuff->srcY * length)); + else + (*shmFuncs[pDraw->pScreen->myNum]->PutImage) (pDraw, pGC, stuff->depth, + stuff->format, + stuff->totalWidth, + stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, + stuff->srcHeight, + stuff->dstX, stuff->dstY, + shmdesc->addr + + stuff->offset); + + if (stuff->sendEvent) { + xShmCompletionEvent ev; + + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = X_ShmPutImage; + ev.majorEvent = ShmReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + + return (client->noClientException); +} + +static int +ProcShmGetImage(client) +ClientPtr client; +{ + DrawablePtr pDraw; + + long lenPer = 0, length; + + Mask plane = 0; + + xShmGetImageReply xgi; + + ShmDescPtr shmdesc; + + REQUEST(xShmGetImageReq); + + REQUEST_SIZE_MATCH(xShmGetImageReq); + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { + client->errorValue = stuff->format; + return (BadValue); + } + VERIFY_DRAWABLE(pDraw, stuff->drawable, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + if (pDraw->type == DRAWABLE_WINDOW) { + if ( /* check for being viewable */ + !((WindowPtr) pDraw)->realized || + /* check for being on screen */ + pDraw->x + stuff->x < 0 || + pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width + || pDraw->y + stuff->y < 0 || + pDraw->y + stuff->y + (int) stuff->height > + pDraw->pScreen->height || + /* check for being inside of border */ + stuff->x < -wBorderWidth((WindowPtr) pDraw) || + stuff->x + (int) stuff->width > + wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width || + stuff->y < -wBorderWidth((WindowPtr) pDraw) || + stuff->y + (int) stuff->height > + wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height) + return (BadMatch); + xgi.visual = wVisual(((WindowPtr) pDraw)); + } + else { + if (stuff->x < 0 || + stuff->x + (int) stuff->width > pDraw->width || + stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height) + return (BadMatch); + xgi.visual = None; + } + xgi.type = X_Reply; + xgi.length = 0; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if (stuff->format == ZPixmap) { + length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; + } + else { + lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; + plane = ((Mask) 1) << (pDraw->depth - 1); + /* only planes asked for */ + length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); + } + + VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); + xgi.size = length; + + if (length == 0) { + /* nothing to do */ + } + else if (stuff->format == ZPixmap) { + (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, stuff->planeMask, + shmdesc->addr + stuff->offset); + } + else { + + length = stuff->offset; + for (; plane; plane >>= 1) { + if (stuff->planeMask & plane) { + (*pDraw->pScreen->GetImage) (pDraw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, plane, + shmdesc->addr + length); + length += lenPer; + } + } + } + + if (client->swapped) { + swaps(&xgi.sequenceNumber); + swapl(&xgi.length); + swapl(&xgi.visual); + swapl(&xgi.size); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *) &xgi); + + return (client->noClientException); +} + +static PixmapPtr +fbShmCreatePixmap(pScreen, width, height, depth, addr) +ScreenPtr pScreen; + +int width; + +int height; + +int depth; + +char *addr; +{ + PixmapPtr pPixmap; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth); + if (!pPixmap) + return NullPixmap; + + if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, + BitsPerPixel(depth), + PixmapBytePad(width, depth), + (pointer) addr)) { + (*pScreen->DestroyPixmap) (pPixmap); + return NullPixmap; + } + return pPixmap; +} + +static int +ProcShmCreatePixmap(client) +ClientPtr client; +{ + PixmapPtr pMap; + + DrawablePtr pDraw; + + DepthPtr pDepth; + + int i; + + ShmDescPtr shmdesc; + + REQUEST(xShmCreatePixmapReq); + + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + client->errorValue = stuff->pid; + if (!sharedPixmaps) + return BadImplementation; + LEGAL_NEW_RESOURCE(stuff->pid, client); + VERIFY_GEOMETRABLE(pDraw, stuff->drawable, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + if (!stuff->width || !stuff->height) { + client->errorValue = 0; + return BadValue; + } + if (stuff->depth != 1) { + pDepth = pDraw->pScreen->allowedDepths; + for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } + CreatePmap: + VERIFY_SHMSIZE(shmdesc, stuff->offset, + PixmapBytePad(stuff->width, stuff->depth) * stuff->height, + client); + pMap = + (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap) (pDraw->pScreen, + stuff->width, + stuff->height, + stuff->depth, + shmdesc->addr + + stuff->offset); + if (pMap) { + pMap->devPrivates[shmPixmapPrivate].ptr = (pointer) shmdesc; + shmdesc->refcnt++; + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = stuff->pid; + if (AddResource(stuff->pid, RT_PIXMAP, (pointer) pMap)) { + return (client->noClientException); + } + } + return (BadAlloc); +} + +static int +ProcShmDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_ShmQueryVersion: + return ProcShmQueryVersion(client); + case X_ShmAttach: + return ProcShmAttach(client); + case X_ShmDetach: + return ProcShmDetach(client); + case X_ShmPutImage: + return ProcShmPutImage(client); + case X_ShmGetImage: + return ProcShmGetImage(client); + case X_ShmCreatePixmap: + return ProcShmCreatePixmap(client); + default: + return BadRequest; + } +} + +static void +SShmCompletionEvent(from, to) +xShmCompletionEvent *from, *to; +{ + to->type = from->type; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->drawable, to->drawable); + cpswaps(from->minorEvent, to->minorEvent); + to->majorEvent = from->majorEvent; + cpswapl(from->shmseg, to->shmseg); + cpswapl(from->offset, to->offset); +} + +static int +SProcShmQueryVersion(client) +ClientPtr client; +{ + + REQUEST(xShmQueryVersionReq); + + swaps(&stuff->length); + return ProcShmQueryVersion(client); +} + +static int +SProcShmAttach(client) +ClientPtr client; +{ + + REQUEST(xShmAttachReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShmAttachReq); + swapl(&stuff->shmseg); + swapl(&stuff->shmid); + return ProcShmAttach(client); +} + +static int +SProcShmDetach(client) +ClientPtr client; +{ + + REQUEST(xShmDetachReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShmDetachReq); + swapl(&stuff->shmseg); + return ProcShmDetach(client); +} + +static int +SProcShmPutImage(client) +ClientPtr client; +{ + + REQUEST(xShmPutImageReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShmPutImageReq); + swapl(&stuff->drawable); + swapl(&stuff->gc); + swaps(&stuff->totalWidth); + swaps(&stuff->totalHeight); + swaps(&stuff->srcX); + swaps(&stuff->srcY); + swaps(&stuff->srcWidth); + swaps(&stuff->srcHeight); + swaps(&stuff->dstX); + swaps(&stuff->dstY); + swapl(&stuff->shmseg); + swapl(&stuff->offset); + return ProcShmPutImage(client); +} + +static int +SProcShmGetImage(client) +ClientPtr client; +{ + + REQUEST(xShmGetImageReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShmGetImageReq); + swapl(&stuff->drawable); + swaps(&stuff->x); + swaps(&stuff->y); + swaps(&stuff->width); + swaps(&stuff->height); + swapl(&stuff->planeMask); + swapl(&stuff->shmseg); + swapl(&stuff->offset); + return ProcShmGetImage(client); +} + +static int +SProcShmCreatePixmap(client) +ClientPtr client; +{ + + REQUEST(xShmCreatePixmapReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + swapl(&stuff->pid); + swapl(&stuff->drawable); + swaps(&stuff->width); + swaps(&stuff->height); + swapl(&stuff->shmseg); + swapl(&stuff->offset); + return ProcShmCreatePixmap(client); +} + +static int +SProcShmDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_ShmQueryVersion: + return SProcShmQueryVersion(client); + case X_ShmAttach: + return SProcShmAttach(client); + case X_ShmDetach: + return SProcShmDetach(client); + case X_ShmPutImage: + return SProcShmPutImage(client); + case X_ShmGetImage: + return SProcShmGetImage(client); + case X_ShmCreatePixmap: + return SProcShmCreatePixmap(client); + default: + return BadRequest; + } +} diff --git a/Xext/shmint.h b/Xext/shmint.h new file mode 100644 index 0000000..0b5367e --- /dev/null +++ b/Xext/shmint.h @@ -0,0 +1,43 @@ +/* + * + * Copyright © 2003 Keith Packard + * + * 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 both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SHMINT_H_ +#define _SHMINT_H_ + +#define _XSHM_SERVER_ +#include + +#include "screenint.h" +#include "pixmap.h" +#include "gc.h" + +void + ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs); + +void + ShmSetPixmapFormat(ScreenPtr pScreen, int format); + +void + ShmRegisterFbFuncs(ScreenPtr pScreen); + +#endif /* _SHMINT_H_ */ diff --git a/Xext/sleepuntil.c b/Xext/sleepuntil.c new file mode 100644 index 0000000..5952614 --- /dev/null +++ b/Xext/sleepuntil.c @@ -0,0 +1,240 @@ +/* + * +Copyright 1992, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* dixsleep.c - implement millisecond timeouts for X clients */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "sleepuntil.h" +#include +#include +#include "misc.h" +#include "windowstr.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "scrnintstr.h" + +typedef struct _Sertafied { + struct _Sertafied *next; + TimeStamp revive; + ClientPtr pClient; + XID id; + void (*notifyFunc) (ClientPtr /* client */ , + pointer /* closure */ + ); + + pointer closure; +} SertafiedRec, *SertafiedPtr; + +static SertafiedPtr pPending; + +static RESTYPE SertafiedResType; + +static Bool BlockHandlerRegistered; + +static int SertafiedGeneration; + +static void ClientAwaken(ClientPtr /* client */ , + pointer /* closure */ + ); + +static int SertafiedDelete(pointer /* value */ , + XID /* id */ + ); + +static void SertafiedBlockHandler(pointer /* data */ , + OSTimePtr /* wt */ , + pointer /* LastSelectMask */ + ); + +static void SertafiedWakeupHandler(pointer /* data */ , + int /* i */ , + pointer /* LastSelectMask */ + ); + +_X_EXPORT int +ClientSleepUntil(client, revive, notifyFunc, closure) +ClientPtr client; + +TimeStamp *revive; + +void (*notifyFunc) (ClientPtr /* client */ , + pointer /* closure */ ); + +pointer closure; +{ + SertafiedPtr pRequest, pReq, pPrev; + + if (SertafiedGeneration != serverGeneration) { + SertafiedResType = CreateNewResourceType(SertafiedDelete); + if (!SertafiedResType) + return FALSE; + SertafiedGeneration = serverGeneration; + BlockHandlerRegistered = FALSE; + } + pRequest = malloc(sizeof(SertafiedRec)); + if (!pRequest) + return FALSE; + pRequest->pClient = client; + pRequest->revive = *revive; + pRequest->id = FakeClientID(client->index); + pRequest->closure = closure; + if (!BlockHandlerRegistered) { + if (!RegisterBlockAndWakeupHandlers(SertafiedBlockHandler, + SertafiedWakeupHandler, + (pointer) 0)) { + free(pRequest); + return FALSE; + } + BlockHandlerRegistered = TRUE; + } + pRequest->notifyFunc = 0; + if (!AddResource(pRequest->id, SertafiedResType, (pointer) pRequest)) + return FALSE; + if (!notifyFunc) + notifyFunc = ClientAwaken; + pRequest->notifyFunc = notifyFunc; + /* Insert into time-ordered queue, with earliest activation time coming first. */ + pPrev = 0; + for (pReq = pPending; pReq; pReq = pReq->next) { + if (CompareTimeStamps(pReq->revive, *revive) == LATER) + break; + pPrev = pReq; + } + if (pPrev) + pPrev->next = pRequest; + else + pPending = pRequest; + pRequest->next = pReq; + IgnoreClient(client); + return TRUE; +} + +static void +ClientAwaken(client, closure) +ClientPtr client; + +pointer closure; +{ + if (!client->clientGone) + AttendClient(client); +} + +static int +SertafiedDelete(value, id) +pointer value; + +XID id; +{ + SertafiedPtr pRequest = (SertafiedPtr) value; + + SertafiedPtr pReq, pPrev; + + pPrev = 0; + for (pReq = pPending; pReq; pPrev = pReq, pReq = pReq->next) + if (pReq == pRequest) { + if (pPrev) + pPrev->next = pReq->next; + else + pPending = pReq->next; + break; + } + if (pRequest->notifyFunc) + (*pRequest->notifyFunc) (pRequest->pClient, pRequest->closure); + free(pRequest); + return TRUE; +} + +static void +SertafiedBlockHandler(data, wt, LastSelectMask) +pointer data; /* unused */ + +OSTimePtr wt; /* wait time */ + +pointer LastSelectMask; +{ + SertafiedPtr pReq, pNext; + + unsigned long delay; + + TimeStamp now; + + if (!pPending) + return; + now.milliseconds = GetTimeInMillis(); + now.months = currentTime.months; + if ((int) (now.milliseconds - currentTime.milliseconds) < 0) + now.months++; + for (pReq = pPending; pReq; pReq = pNext) { + pNext = pReq->next; + if (CompareTimeStamps(pReq->revive, now) == LATER) + break; + FreeResource(pReq->id, RT_NONE); + + /* AttendClient() may have been called via the resource delete + * function so a client may have input to be processed and so + * set delay to 0 to prevent blocking in WaitForSomething(). + */ + AdjustWaitForDelay(wt, 0); + } + pReq = pPending; + if (!pReq) + return; + delay = pReq->revive.milliseconds - now.milliseconds; + AdjustWaitForDelay(wt, delay); +} + +static void +SertafiedWakeupHandler(data, i, LastSelectMask) +pointer data; + +int i; + +pointer LastSelectMask; +{ + SertafiedPtr pReq, pNext; + + TimeStamp now; + + now.milliseconds = GetTimeInMillis(); + now.months = currentTime.months; + if ((int) (now.milliseconds - currentTime.milliseconds) < 0) + now.months++; + for (pReq = pPending; pReq; pReq = pNext) { + pNext = pReq->next; + if (CompareTimeStamps(pReq->revive, now) == LATER) + break; + FreeResource(pReq->id, RT_NONE); + } + if (!pPending) { + RemoveBlockAndWakeupHandlers(SertafiedBlockHandler, + SertafiedWakeupHandler, (pointer) 0); + BlockHandlerRegistered = FALSE; + } +} diff --git a/Xext/sleepuntil.h b/Xext/sleepuntil.h new file mode 100644 index 0000000..5c70848 --- /dev/null +++ b/Xext/sleepuntil.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2001 The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the XFree86 Project shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from the + * XFree86 Project. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef _SLEEPUNTIL_H_ +#define _SLEEPUNTIL_H_ 1 + +#include "dix.h" + +extern int ClientSleepUntil(ClientPtr client, + TimeStamp *revive, + void (*notifyFunc) (ClientPtr /* client */ , + pointer /* closure */ + ), pointer Closure); + +#endif diff --git a/Xext/sync.c b/Xext/sync.c new file mode 100644 index 0000000..88ad5e6 --- /dev/null +++ b/Xext/sync.c @@ -0,0 +1,2456 @@ +/* + +Copyright 1991, 1993, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts, +and Olivetti Research Limited, Cambridge, England. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Olivetti +not be used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. Digital and Olivetti +make no representations about the suitability of this software +for any purpose. It is provided "as is" without express or implied warranty. + +DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF +USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include "misc.h" +#include "os.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" +#define _SYNC_SERVER +#include +#include + +#include +#include + +#include "extinit.h" + +/* + * Local Global Variables + */ +static int SyncEventBase; + +static int SyncErrorBase; + +static RESTYPE RTCounter = 0; + +static RESTYPE RTAwait; + +static RESTYPE RTAlarm; + +static RESTYPE RTAlarmClient; + +static int SyncNumSystemCounters = 0; + +static SyncCounter **SysCounterList = NULL; + +#define IsSystemCounter(pCounter) \ + (pCounter && (pCounter->client == NULL)) + +/* these are all the alarm attributes that pertain to the alarm's trigger */ +#define XSyncCAAllTrigger \ + (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType) + +static int + FreeAlarm(pointer /* addr */ , + XID /* id */ + ); + +static int + FreeAlarmClient(pointer /* value */ , + XID /* id */ + ); + +static int + FreeAwait(pointer /* addr */ , + XID /* id */ + ); + +static void + ServertimeBracketValues(pointer /* pCounter */ , + CARD64 * /* pbracket_less */ , + CARD64 * /* pbracket_greater */ + ); + +static void + ServertimeQueryValue(pointer /* pCounter */ , + CARD64 * /* pValue_return */ + ); + +static void + ServertimeWakeupHandler(pointer /* env */ , + int /* rc */ , + pointer /* LastSelectMask */ + ); + +static int + SyncInitTrigger(ClientPtr /* client */ , + SyncTrigger * /* pTrigger */ , + XSyncCounter /* counter */ , + Mask /* changes */ + ); + +static void + SAlarmNotifyEvent(xSyncAlarmNotifyEvent * /* from */ , + xSyncAlarmNotifyEvent * /* to */ + ); + +static void + SCounterNotifyEvent(xSyncCounterNotifyEvent * /* from */ , + xSyncCounterNotifyEvent * /* to */ + ); + +static void + ServertimeBlockHandler(pointer /* env */ , + struct timeval ** /* wt */ , + pointer /* LastSelectMask */ + ); + +static int + SyncAddTriggerToCounter(SyncTrigger * /* pTrigger */ + ); + +extern void + SyncAlarmCounterDestroyed(SyncTrigger * /* pTrigger */ + ); + +static void + SyncAlarmTriggerFired(SyncTrigger * /* pTrigger */ + ); + +static void + SyncAwaitTriggerFired(SyncTrigger * /* pTrigger */ + ); + +static int + SyncChangeAlarmAttributes(ClientPtr /* client */ , + SyncAlarm * /* pAlarm */ , + Mask /* mask */ , + CARD32 * /* values */ + ); + +static Bool + SyncCheckTriggerNegativeComparison(SyncTrigger * /* pTrigger */ , + CARD64 /* oldval */ + ); + +static Bool + SyncCheckTriggerNegativeTransition(SyncTrigger * /* pTrigger */ , + CARD64 /* oldval */ + ); + +static Bool + SyncCheckTriggerPositiveComparison(SyncTrigger * /* pTrigger */ , + CARD64 /* oldval */ + ); + +static Bool + SyncCheckTriggerPositiveTransition(SyncTrigger * /* pTrigger */ , + CARD64 /* oldval */ + ); + +static SyncCounter *SyncCreateCounter(ClientPtr /* client */ , + XSyncCounter /* id */ , + CARD64 /* initialvalue */ + ); + +static void SyncComputeBracketValues(SyncCounter * /* pCounter */ , + Bool /* startOver */ + ); + +static void + SyncDeleteTriggerFromCounter(SyncTrigger * /* pTrigger */ + ); + +static Bool + SyncEventSelectForAlarm(SyncAlarm * /* pAlarm */ , + ClientPtr /* client */ , + Bool /* wantevents */ + ); + +static void + SyncInitServerTime(void + ); + +static void + SyncResetProc(ExtensionEntry * /* extEntry */ + ); + +static void + SyncSendAlarmNotifyEvents(SyncAlarm * /* pAlarm */ + ); + +static void + SyncSendCounterNotifyEvents(ClientPtr /* client */ , + SyncAwait ** /* ppAwait */ , + int /* num_events */ + ); + +static DISPATCH_PROC(ProcSyncAwait); + +static DISPATCH_PROC(ProcSyncChangeAlarm); + +static DISPATCH_PROC(ProcSyncChangeCounter); + +static DISPATCH_PROC(ProcSyncCreateAlarm); + +static DISPATCH_PROC(ProcSyncCreateCounter); + +static DISPATCH_PROC(ProcSyncDestroyAlarm); + +static DISPATCH_PROC(ProcSyncDestroyCounter); + +static DISPATCH_PROC(ProcSyncDispatch); + +static DISPATCH_PROC(ProcSyncGetPriority); + +static DISPATCH_PROC(ProcSyncInitialize); + +static DISPATCH_PROC(ProcSyncListSystemCounters); + +static DISPATCH_PROC(ProcSyncQueryAlarm); + +static DISPATCH_PROC(ProcSyncQueryCounter); + +static DISPATCH_PROC(ProcSyncSetCounter); + +static DISPATCH_PROC(ProcSyncSetPriority); + +static DISPATCH_PROC(SProcSyncAwait); + +static DISPATCH_PROC(SProcSyncChangeAlarm); + +static DISPATCH_PROC(SProcSyncChangeCounter); + +static DISPATCH_PROC(SProcSyncCreateAlarm); + +static DISPATCH_PROC(SProcSyncCreateCounter); + +static DISPATCH_PROC(SProcSyncDestroyAlarm); + +static DISPATCH_PROC(SProcSyncDestroyCounter); + +static DISPATCH_PROC(SProcSyncDispatch); + +static DISPATCH_PROC(SProcSyncGetPriority); + +static DISPATCH_PROC(SProcSyncInitialize); + +static DISPATCH_PROC(SProcSyncListSystemCounters); + +static DISPATCH_PROC(SProcSyncQueryAlarm); + +static DISPATCH_PROC(SProcSyncQueryCounter); + +static DISPATCH_PROC(SProcSyncSetCounter); + +static DISPATCH_PROC(SProcSyncSetPriority); + +/* Each counter maintains a simple linked list of triggers that are + * interested in the counter. The two functions below are used to + * delete and add triggers on this list. + */ +static void +SyncDeleteTriggerFromCounter(pTrigger) +SyncTrigger *pTrigger; +{ + SyncTriggerList *pCur; + + SyncTriggerList *pPrev; + + /* pCounter needs to be stored in pTrigger before calling here. */ + + if (!pTrigger->pCounter) + return; + + pPrev = NULL; + pCur = pTrigger->pCounter->pTriglist; + + while (pCur) { + if (pCur->pTrigger == pTrigger) { + if (pPrev) + pPrev->next = pCur->next; + else + pTrigger->pCounter->pTriglist = pCur->next; + + free(pCur); + break; + } + + pPrev = pCur; + pCur = pCur->next; + } + + if (IsSystemCounter(pTrigger->pCounter)) + SyncComputeBracketValues(pTrigger->pCounter, /*startOver */ TRUE); +} + +static int +SyncAddTriggerToCounter(pTrigger) +SyncTrigger *pTrigger; +{ + SyncTriggerList *pCur; + + if (!pTrigger->pCounter) + return Success; + + /* don't do anything if it's already there */ + for (pCur = pTrigger->pCounter->pTriglist; pCur; pCur = pCur->next) { + if (pCur->pTrigger == pTrigger) + return Success; + } + + if (!(pCur = malloc(sizeof(SyncTriggerList)))) + return BadAlloc; + + pCur->pTrigger = pTrigger; + pCur->next = pTrigger->pCounter->pTriglist; + pTrigger->pCounter->pTriglist = pCur; + + if (IsSystemCounter(pTrigger->pCounter)) + SyncComputeBracketValues(pTrigger->pCounter, /*startOver */ TRUE); + + return Success; +} + +/* Below are four possible functions that can be plugged into + * pTrigger->CheckTrigger, corresponding to the four possible + * test-types. These functions are called after the counter's + * value changes but are also passed the old counter value + * so they can inspect both the old and new values. + * (PositiveTransition and NegativeTransition need to see both + * pieces of information.) These functions return the truth value + * of the trigger. + * + * All of them include the condition pTrigger->pCounter == NULL. + * This is because the spec says that a trigger with a counter value + * of None is always TRUE. + */ + +static Bool +SyncCheckTriggerPositiveComparison(pTrigger, oldval) +SyncTrigger *pTrigger; + +CARD64 oldval; +{ + return (pTrigger->pCounter == NULL || + XSyncValueGreaterOrEqual(pTrigger->pCounter->value, + pTrigger->test_value)); +} + +static Bool +SyncCheckTriggerNegativeComparison(pTrigger, oldval) +SyncTrigger *pTrigger; + +CARD64 oldval; +{ + return (pTrigger->pCounter == NULL || + XSyncValueLessOrEqual(pTrigger->pCounter->value, + pTrigger->test_value)); +} + +static Bool +SyncCheckTriggerPositiveTransition(pTrigger, oldval) +SyncTrigger *pTrigger; + +CARD64 oldval; +{ + return (pTrigger->pCounter == NULL || + (XSyncValueLessThan(oldval, pTrigger->test_value) && + XSyncValueGreaterOrEqual(pTrigger->pCounter->value, + pTrigger->test_value))); +} + +static Bool +SyncCheckTriggerNegativeTransition(pTrigger, oldval) +SyncTrigger *pTrigger; + +CARD64 oldval; +{ + return (pTrigger->pCounter == NULL || + (XSyncValueGreaterThan(oldval, pTrigger->test_value) && + XSyncValueLessOrEqual(pTrigger->pCounter->value, + pTrigger->test_value))); +} + +static int +SyncInitTrigger(client, pTrigger, counter, changes) +ClientPtr client; /* so we can set errorValue */ + +SyncTrigger *pTrigger; + +XSyncCounter counter; + +Mask changes; +{ + SyncCounter *pCounter = pTrigger->pCounter; + + int status; + + Bool newcounter = FALSE; + + if (changes & XSyncCACounter) { + if (counter == None) + pCounter = NULL; + else if (! + (pCounter = + (SyncCounter *) SecurityLookupIDByType(client, counter, + RTCounter, + SecurityReadAccess))) { + client->errorValue = counter; + return SyncErrorBase + XSyncBadCounter; + } + if (pCounter != pTrigger->pCounter) { /* new counter for trigger */ + SyncDeleteTriggerFromCounter(pTrigger); + pTrigger->pCounter = pCounter; + newcounter = TRUE; + } + } + + /* if system counter, ask it what the current value is */ + + if (IsSystemCounter(pCounter)) { + (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter, + &pCounter->value); + } + + if (changes & XSyncCAValueType) { + if (pTrigger->value_type != XSyncRelative && + pTrigger->value_type != XSyncAbsolute) { + client->errorValue = pTrigger->value_type; + return BadValue; + } + } + + if (changes & XSyncCATestType) { + if (pTrigger->test_type != XSyncPositiveTransition && + pTrigger->test_type != XSyncNegativeTransition && + pTrigger->test_type != XSyncPositiveComparison && + pTrigger->test_type != XSyncNegativeComparison) { + client->errorValue = pTrigger->test_type; + return BadValue; + } + /* select appropriate CheckTrigger function */ + + switch (pTrigger->test_type) { + case XSyncPositiveTransition: + pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition; + break; + case XSyncNegativeTransition: + pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition; + break; + case XSyncPositiveComparison: + pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison; + break; + case XSyncNegativeComparison: + pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison; + break; + } + } + + if (changes & (XSyncCAValueType | XSyncCAValue)) { + if (pTrigger->value_type == XSyncAbsolute) + pTrigger->test_value = pTrigger->wait_value; + else { /* relative */ + + Bool overflow; + + if (pCounter == NULL) + return BadMatch; + + XSyncValueAdd(&pTrigger->test_value, pCounter->value, + pTrigger->wait_value, &overflow); + if (overflow) { + client->errorValue = XSyncValueHigh32(pTrigger->wait_value); + return BadValue; + } + } + } + + /* we wait until we're sure there are no errors before registering + * a new counter on a trigger + */ + if (newcounter) { + if ((status = SyncAddTriggerToCounter(pTrigger)) != Success) + return status; + } + else if (IsSystemCounter(pCounter)) { + SyncComputeBracketValues(pCounter, /*startOver */ TRUE); + } + + return Success; +} + +/* AlarmNotify events happen in response to actions taken on an Alarm or + * the counter used by the alarm. AlarmNotify may be sent to multiple + * clients. The alarm maintains a list of clients interested in events. + */ +static void +SyncSendAlarmNotifyEvents(pAlarm) +SyncAlarm *pAlarm; +{ + SyncAlarmClientList *pcl; + + xSyncAlarmNotifyEvent ane; + + SyncTrigger *pTrigger = &pAlarm->trigger; + + UpdateCurrentTime(); + + ane.type = SyncEventBase + XSyncAlarmNotify; + ane.kind = XSyncAlarmNotify; + ane.sequenceNumber = pAlarm->client->sequence; + ane.alarm = pAlarm->alarm_id; + if (pTrigger->pCounter) { + ane.counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value); + ane.counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value); + } + else { /* XXX what else can we do if there's no counter? */ + ane.counter_value_hi = ane.counter_value_lo = 0; + } + + ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value); + ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value); + ane.time = currentTime.milliseconds; + ane.state = pAlarm->state; + + /* send to owner */ + if (pAlarm->events && !pAlarm->client->clientGone) + WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane); + + /* send to other interested clients */ + for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next) { + if (!pAlarm->client->clientGone) { + ane.sequenceNumber = pcl->client->sequence; + WriteEventsToClient(pcl->client, 1, (xEvent *) &ane); + } + } +} + +/* CounterNotify events only occur in response to an Await. The events + * go only to the Awaiting client. + */ +static void +SyncSendCounterNotifyEvents(client, ppAwait, num_events) +ClientPtr client; + +SyncAwait **ppAwait; + +int num_events; +{ + xSyncCounterNotifyEvent *pEvents, *pev; + + int i; + + if (client->clientGone) + return; + pev = pEvents = (xSyncCounterNotifyEvent *) + ALLOCATE_LOCAL(num_events * sizeof(xSyncCounterNotifyEvent)); + if (!pEvents) + return; + UpdateCurrentTime(); + for (i = 0; i < num_events; i++, ppAwait++, pev++) { + SyncTrigger *pTrigger = &(*ppAwait)->trigger; + + pev->type = SyncEventBase + XSyncCounterNotify; + pev->kind = XSyncCounterNotify; + pev->sequenceNumber = client->sequence; + pev->counter = pTrigger->pCounter->id; + pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value); + pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value); + pev->counter_value_lo = XSyncValueLow32(pTrigger->pCounter->value); + pev->counter_value_hi = XSyncValueHigh32(pTrigger->pCounter->value); + pev->time = currentTime.milliseconds; + pev->count = num_events - i - 1; /* events remaining */ + pev->destroyed = pTrigger->pCounter->beingDestroyed; + } + /* swapping will be taken care of by this */ + WriteEventsToClient(client, num_events, (xEvent *) pEvents); + DEALLOCATE_LOCAL(pEvents); +} + +/* This function is called when an alarm's counter is destroyed. + * It is plugged into pTrigger->CounterDestroyed (for alarm triggers). + */ +void +SyncAlarmCounterDestroyed(pTrigger) +SyncTrigger *pTrigger; +{ + SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; + + pAlarm->state = XSyncAlarmInactive; + SyncSendAlarmNotifyEvents(pAlarm); + pTrigger->pCounter = NULL; +} + +/* This function is called when an alarm "goes off." + * It is plugged into pTrigger->TriggerFired (for alarm triggers). + */ +static void +SyncAlarmTriggerFired(pTrigger) +SyncTrigger *pTrigger; +{ + SyncAlarm *pAlarm = (SyncAlarm *) pTrigger; + + CARD64 new_test_value; + + /* no need to check alarm unless it's active */ + if (pAlarm->state != XSyncAlarmActive) + return; + + /* " if the counter value is None, or if the delta is 0 and + * the test-type is PositiveComparison or NegativeComparison, + * no change is made to value (test-value) and the alarm + * state is changed to Inactive before the event is generated." + */ + if (pAlarm->trigger.pCounter == NULL || (XSyncValueIsZero(pAlarm->delta) + && (pAlarm->trigger.test_type == + XSyncPositiveComparison || + pAlarm->trigger.test_type == + XSyncNegativeComparison))) + pAlarm->state = XSyncAlarmInactive; + + new_test_value = pAlarm->trigger.test_value; + + if (pAlarm->state == XSyncAlarmActive) { + Bool overflow; + + CARD64 oldvalue; + + SyncTrigger *paTrigger = &pAlarm->trigger; + + /* "The alarm is updated by repeatedly adding delta to the + * value of the trigger and re-initializing it until it + * becomes FALSE." + */ + oldvalue = paTrigger->test_value; + + /* XXX really should do something smarter here */ + + do { + XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value, + pAlarm->delta, &overflow); + } while (!overflow && + (*paTrigger->CheckTrigger) (paTrigger, + paTrigger->pCounter->value)); + + new_test_value = paTrigger->test_value; + paTrigger->test_value = oldvalue; + + /* "If this update would cause value to fall outside the range + * for an INT64...no change is made to value (test-value) and + * the alarm state is changed to Inactive before the event is + * generated." + */ + if (overflow) { + new_test_value = oldvalue; + pAlarm->state = XSyncAlarmInactive; + } + } + /* The AlarmNotify event has to have the "new state of the alarm" + * which we can't be sure of until this point. However, it has + * to have the "old" trigger test value. That's the reason for + * all the newvalue/oldvalue shuffling above. After we send the + * events, give the trigger its new test value. + */ + SyncSendAlarmNotifyEvents(pAlarm); + pTrigger->test_value = new_test_value; +} + +/* This function is called when an Await unblocks, either as a result + * of the trigger firing OR the counter being destroyed. + * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed + * (for Await triggers). + */ +static void +SyncAwaitTriggerFired(pTrigger) +SyncTrigger *pTrigger; +{ + SyncAwait *pAwait = (SyncAwait *) pTrigger; + + int numwaits; + + SyncAwaitUnion *pAwaitUnion; + + SyncAwait **ppAwait; + + int num_events = 0; + + pAwaitUnion = (SyncAwaitUnion *) pAwait->pHeader; + numwaits = pAwaitUnion->header.num_waitconditions; + ppAwait = (SyncAwait **) ALLOCATE_LOCAL(numwaits * sizeof(SyncAwait *)); + if (!ppAwait) + goto bail; + + pAwait = &(pAwaitUnion + 1)->await; + + /* "When a client is unblocked, all the CounterNotify events for + * the Await request are generated contiguously. If count is 0 + * there are no more events to follow for this request. If + * count is n, there are at least n more events to follow." + * + * Thus, it is best to find all the counters for which events + * need to be sent first, so that an accurate count field can + * be stored in the events. + */ + for (; numwaits; numwaits--, pAwait++) { + CARD64 diff; + + Bool overflow, diffgreater, diffequal; + + /* "A CounterNotify event with the destroyed flag set to TRUE is + * always generated if the counter for one of the triggers is + * destroyed." + */ + if (pAwait->trigger.pCounter->beingDestroyed) { + ppAwait[num_events++] = pAwait; + continue; + } + + /* "The difference between the counter and the test value is + * calculated by subtracting the test value from the value of + * the counter." + */ + XSyncValueSubtract(&diff, pAwait->trigger.pCounter->value, + pAwait->trigger.test_value, &overflow); + + /* "If the difference lies outside the range for an INT64, an + * event is not generated." + */ + if (overflow) + continue; + diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold); + diffequal = XSyncValueEqual(diff, pAwait->event_threshold); + + /* "If the test-type is PositiveTransition or + * PositiveComparison, a CounterNotify event is generated if + * the difference is at least event-threshold. If the test-type + * is NegativeTransition or NegativeComparison, a CounterNotify + * event is generated if the difference is at most + * event-threshold." + */ + + if (((pAwait->trigger.test_type == XSyncPositiveComparison || + pAwait->trigger.test_type == XSyncPositiveTransition) + && (diffgreater || diffequal)) + || + ((pAwait->trigger.test_type == XSyncNegativeComparison || + pAwait->trigger.test_type == XSyncNegativeTransition) + && (!diffgreater) /* less or equal */ + ) + ) { + ppAwait[num_events++] = pAwait; + } + } + if (num_events) + SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait, + num_events); + DEALLOCATE_LOCAL(ppAwait); + + bail: + /* unblock the client */ + AttendClient(pAwaitUnion->header.client); + /* delete the await */ + FreeResource(pAwaitUnion->header.delete_id, RT_NONE); +} + +/* This function should always be used to change a counter's value so that + * any triggers depending on the counter will be checked. + */ +void +SyncChangeCounter(pCounter, newval) +SyncCounter *pCounter; + +CARD64 newval; +{ + SyncTriggerList *ptl, *pnext; + + CARD64 oldval; + + oldval = pCounter->value; + pCounter->value = newval; + + /* run through triggers to see if any become true */ + for (ptl = pCounter->pTriglist; ptl; ptl = pnext) { + pnext = ptl->next; + if ((*ptl->pTrigger->CheckTrigger) (ptl->pTrigger, oldval)) + (*ptl->pTrigger->TriggerFired) (ptl->pTrigger); + } + + if (IsSystemCounter(pCounter)) { + SyncComputeBracketValues(pCounter, /* startOver */ FALSE); + } +} + +/* loosely based on dix/events.c/EventSelectForWindow */ +static Bool +SyncEventSelectForAlarm(pAlarm, client, wantevents) +SyncAlarm *pAlarm; + +ClientPtr client; + +Bool wantevents; +{ + SyncAlarmClientList *pClients; + + if (client == pAlarm->client) { /* alarm owner */ + pAlarm->events = wantevents; + return Success; + } + + /* see if the client is already on the list (has events selected) */ + + for (pClients = pAlarm->pEventClients; pClients; pClients = pClients->next) { + if (pClients->client == client) { + /* client's presence on the list indicates desire for + * events. If the client doesn't want events, remove it + * from the list. If the client does want events, do + * nothing, since it's already got them. + */ + if (!wantevents) { + FreeResource(pClients->delete_id, RT_NONE); + } + return Success; + } + } + + /* if we get here, this client does not currently have + * events selected on the alarm + */ + + if (!wantevents) + /* client doesn't want events, and we just discovered that it + * doesn't have them, so there's nothing to do. + */ + return Success; + + /* add new client to pAlarm->pEventClients */ + + pClients = malloc(sizeof(SyncAlarmClientList)); + if (!pClients) + return BadAlloc; + + /* register it as a resource so it will be cleaned up + * if the client dies + */ + + pClients->delete_id = FakeClientID(client->index); + if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm)) { + free(pClients); + return BadAlloc; + } + + /* link it into list after we know all the allocations succeed */ + + pClients->next = pAlarm->pEventClients; + pAlarm->pEventClients = pClients; + pClients->client = client; + return Success; +} + +/* + * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm + */ +static int +SyncChangeAlarmAttributes(client, pAlarm, mask, values) +ClientPtr client; + +SyncAlarm *pAlarm; + +Mask mask; + +CARD32 *values; +{ + int status; + + XSyncCounter counter; + + Mask origmask = mask; + + counter = pAlarm->trigger.pCounter ? pAlarm->trigger.pCounter->id : None; + + while (mask) { + int index2 = lowbit(mask); + + mask &= ~index2; + switch (index2) { + case XSyncCACounter: + mask &= ~XSyncCACounter; + /* sanity check in SyncInitTrigger */ + counter = *values++; + break; + + case XSyncCAValueType: + mask &= ~XSyncCAValueType; + /* sanity check in SyncInitTrigger */ + pAlarm->trigger.value_type = *values++; + break; + + case XSyncCAValue: + mask &= ~XSyncCAValue; + XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]); + values += 2; + break; + + case XSyncCATestType: + mask &= ~XSyncCATestType; + /* sanity check in SyncInitTrigger */ + pAlarm->trigger.test_type = *values++; + break; + + case XSyncCADelta: + mask &= ~XSyncCADelta; + XSyncIntsToValue(&pAlarm->delta, values[1], values[0]); + values += 2; + break; + + case XSyncCAEvents: + mask &= ~XSyncCAEvents; + if ((*values != xTrue) && (*values != xFalse)) { + client->errorValue = *values; + return BadValue; + } + status = SyncEventSelectForAlarm(pAlarm, client, + (Bool) (*values++)); + if (status != Success) + return status; + break; + + default: + client->errorValue = mask; + return BadValue; + } + } + + /* "If the test-type is PositiveComparison or PositiveTransition + * and delta is less than zero, or if the test-type is + * NegativeComparison or NegativeTransition and delta is + * greater than zero, a Match error is generated." + */ + if (origmask & (XSyncCADelta | XSyncCATestType)) { + CARD64 zero; + + XSyncIntToValue(&zero, 0); + if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) || + (pAlarm->trigger.test_type == XSyncPositiveTransition)) + && XSyncValueLessThan(pAlarm->delta, zero)) + || + (((pAlarm->trigger.test_type == XSyncNegativeComparison) || + (pAlarm->trigger.test_type == XSyncNegativeTransition)) + && XSyncValueGreaterThan(pAlarm->delta, zero)) + ) { + return BadMatch; + } + } + + /* postpone this until now, when we're sure nothing else can go wrong */ + if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, + origmask & XSyncCAAllTrigger)) != Success) + return status; + + /* XXX spec does not really say to do this - needs clarification */ + pAlarm->state = XSyncAlarmActive; + return Success; +} + +static SyncCounter * +SyncCreateCounter(client, id, initialvalue) +ClientPtr client; + +XSyncCounter id; + +CARD64 initialvalue; +{ + SyncCounter *pCounter; + + if (!(pCounter = malloc(sizeof(SyncCounter)))) + return (SyncCounter *) NULL; + + if (!AddResource(id, RTCounter, (pointer) pCounter)) { + free((pointer) pCounter); + return (SyncCounter *) NULL; + } + + pCounter->client = client; + pCounter->id = id; + pCounter->value = initialvalue; + pCounter->pTriglist = NULL; + pCounter->beingDestroyed = FALSE; + pCounter->pSysCounterInfo = NULL; + return pCounter; +} + +static int FreeCounter(pointer /*env */ , + XID /*id */ + ); + +/* + * ***** System Counter utilities + */ + +pointer +SyncCreateSystemCounter(name, initial, resolution, counterType, + QueryValue, BracketValues) +char *name; + +CARD64 initial; + +CARD64 resolution; + +SyncCounterType counterType; + +void (*QueryValue) (pointer /* pCounter */ , + CARD64 * /* pValue_return */ ); + +void (*BracketValues) (pointer /* pCounter */ , + CARD64 * /* pbracket_less */ , + CARD64 * /* pbracket_greater */ ); +{ + SyncCounter *pCounter; + + SysCounterList = (SyncCounter **) realloc(SysCounterList, + (SyncNumSystemCounters + + 1) * sizeof(SyncCounter *)); + if (!SysCounterList) + return (pointer) NULL; + + /* this function may be called before SYNC has been initialized, so we + * have to make sure RTCounter is created. + */ + if (RTCounter == 0) { + RTCounter = CreateNewResourceType(FreeCounter); + if (RTCounter == 0) { + return (pointer) NULL; + } + } + + pCounter = SyncCreateCounter((ClientPtr) NULL, FakeClientID(0), initial); + + if (pCounter) { + SysCounterInfo *psci; + + psci = malloc(sizeof(SysCounterInfo)); + if (!psci) { + FreeResource(pCounter->id, RT_NONE); + return (pointer) pCounter; + } + pCounter->pSysCounterInfo = psci; + psci->name = name; + psci->resolution = resolution; + psci->counterType = counterType; + psci->QueryValue = QueryValue; + psci->BracketValues = BracketValues; + XSyncMaxValue(&psci->bracket_greater); + XSyncMinValue(&psci->bracket_less); + SysCounterList[SyncNumSystemCounters++] = pCounter; + } + return (pointer) pCounter; +} + +static void +SyncComputeBracketValues(pCounter, startOver) +SyncCounter *pCounter; + +Bool startOver; +{ + SyncTriggerList *pCur; + + SyncTrigger *pTrigger; + + SysCounterInfo *psci; + + CARD64 *pnewgtval = NULL; + + CARD64 *pnewltval = NULL; + + SyncCounterType ct; + + if (!pCounter) + return; + + psci = pCounter->pSysCounterInfo; + ct = pCounter->pSysCounterInfo->counterType; + if (ct == XSyncCounterNeverChanges) + return; + + if (startOver) { + XSyncMaxValue(&psci->bracket_greater); + XSyncMinValue(&psci->bracket_less); + } + + for (pCur = pCounter->pTriglist; pCur; pCur = pCur->next) { + pTrigger = pCur->pTrigger; + + if (pTrigger->test_type == XSyncPositiveComparison && + ct != XSyncCounterNeverIncreases) { + if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && + XSyncValueLessThan(pTrigger->test_value, + psci->bracket_greater)) { + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; + } + } + else if (pTrigger->test_type == XSyncNegativeComparison && + ct != XSyncCounterNeverDecreases) { + if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && + XSyncValueGreaterThan(pTrigger->test_value, + psci->bracket_less)) { + psci->bracket_less = pTrigger->test_value; + pnewltval = &psci->bracket_less; + } + } + else if ((pTrigger->test_type == XSyncPositiveTransition && + ct != XSyncCounterNeverIncreases) + || + (pTrigger->test_type == XSyncNegativeTransition && + ct != XSyncCounterNeverDecreases) + ) { + if (XSyncValueLessThan(pCounter->value, pTrigger->test_value)) { + if (XSyncValueLessThan(pTrigger->test_value, + psci->bracket_greater)) { + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; + } + else if (XSyncValueGreaterThan(pTrigger->test_value, + psci->bracket_less)) { + psci->bracket_less = pTrigger->test_value; + pnewltval = &psci->bracket_less; + } + } + } + } /* end for each trigger */ + + if (pnewgtval || pnewltval) { + (*psci->BracketValues) ((pointer) pCounter, pnewltval, pnewgtval); + } +} + +/* + * ***** Resource delete functions + */ + +/* ARGSUSED */ +static int +FreeAlarm(addr, id) +pointer addr; + +XID id; +{ + SyncAlarm *pAlarm = (SyncAlarm *) addr; + + pAlarm->state = XSyncAlarmDestroyed; + + SyncSendAlarmNotifyEvents(pAlarm); + + /* delete event selections */ + + while (pAlarm->pEventClients) + FreeResource(pAlarm->pEventClients->delete_id, RT_NONE); + + SyncDeleteTriggerFromCounter(&pAlarm->trigger); + + free(pAlarm); + return Success; +} + +/* + * ** Cleanup after the destruction of a Counter + */ +/* ARGSUSED */ +static int +FreeCounter(env, id) +pointer env; + +XID id; +{ + SyncCounter *pCounter = (SyncCounter *) env; + + SyncTriggerList *ptl, *pnext; + + pCounter->beingDestroyed = TRUE; + /* tell all the counter's triggers that the counter has been destroyed */ + for (ptl = pCounter->pTriglist; ptl; ptl = pnext) { + (*ptl->pTrigger->CounterDestroyed) (ptl->pTrigger); + pnext = ptl->next; + free(ptl); /* destroy the trigger list as we go */ + } + if (IsSystemCounter(pCounter)) { + int i, found = 0; + + free(pCounter->pSysCounterInfo); + + /* find the counter in the list of system counters and remove it */ + + if (SysCounterList) { + for (i = 0; i < SyncNumSystemCounters; i++) { + if (SysCounterList[i] == pCounter) { + found = i; + break; + } + } + if (found < (SyncNumSystemCounters - 1)) { + for (i = found; i < SyncNumSystemCounters - 1; i++) { + SysCounterList[i] = SysCounterList[i + 1]; + } + } + } + SyncNumSystemCounters--; + } + free(pCounter); + return Success; +} + +/* + * ** Cleanup after Await + */ +/* ARGSUSED */ +static int +FreeAwait(addr, id) +pointer addr; + +XID id; +{ + SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr; + + SyncAwait *pAwait; + + int numwaits; + + pAwait = &(pAwaitUnion + 1)->await; /* first await on list */ + + /* remove triggers from counters */ + + for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits; + numwaits--, pAwait++) { + /* If the counter is being destroyed, FreeCounter will delete + * the trigger list itself, so don't do it here. + */ + SyncCounter *pCounter = pAwait->trigger.pCounter; + + if (pCounter && !pCounter->beingDestroyed) + SyncDeleteTriggerFromCounter(&pAwait->trigger); + } + free(pAwaitUnion); + return Success; +} + +/* loosely based on dix/events.c/OtherClientGone */ +static int +FreeAlarmClient(value, id) +pointer value; /* must conform to DeleteType */ + +XID id; +{ + SyncAlarm *pAlarm = (SyncAlarm *) value; + + SyncAlarmClientList *pCur, *pPrev; + + for (pPrev = NULL, pCur = pAlarm->pEventClients; + pCur; pPrev = pCur, pCur = pCur->next) { + if (pCur->delete_id == id) { + if (pPrev) + pPrev->next = pCur->next; + else + pAlarm->pEventClients = pCur->next; + free(pCur); + return (Success); + } + } + FatalError("alarm client not on event list"); + /*NOTREACHED*/} + +/* + * ***** Proc functions + */ + +/* + * ** Initialize the extension + */ +static int +ProcSyncInitialize(client) +ClientPtr client; +{ + xSyncInitializeReply rep; + + REQUEST_SIZE_MATCH(xSyncInitializeReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SYNC_MAJOR_VERSION; + rep.minorVersion = SYNC_MINOR_VERSION; + rep.length = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + } + WriteToClient(client, sizeof(rep), (char *) &rep); + return (client->noClientException); +} + +/* + * ** Get list of system counters available through the extension + */ +static int +ProcSyncListSystemCounters(client) +ClientPtr client; +{ + xSyncListSystemCountersReply rep; + + int i, len; + + xSyncSystemCounter *list = NULL, *walklist = NULL; + + REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.nCounters = SyncNumSystemCounters; + + for (i = len = 0; i < SyncNumSystemCounters; i++) { + char *name = SysCounterList[i]->pSysCounterInfo->name; + + /* pad to 4 byte boundary */ + len += (sz_xSyncSystemCounter + strlen(name) + 3) & ~3; + } + + if (len) { + walklist = list = (xSyncSystemCounter *) ALLOCATE_LOCAL(len); + if (!list) + return BadAlloc; + } + + rep.length = len >> 2; + + if (client->swapped) { + + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.nCounters); + } + + for (i = 0; i < SyncNumSystemCounters; i++) { + int namelen; + + char *pname_in_reply; + + SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo; + + walklist->counter = SysCounterList[i]->id; + walklist->resolution_hi = XSyncValueHigh32(psci->resolution); + walklist->resolution_lo = XSyncValueLow32(psci->resolution); + namelen = strlen(psci->name); + walklist->name_length = namelen; + + if (client->swapped) { + + swapl(&walklist->counter); + swapl(&walklist->resolution_hi); + swapl(&walklist->resolution_lo); + swaps(&walklist->name_length); + } + + pname_in_reply = ((char *) walklist) + sz_xSyncSystemCounter; + strncpy(pname_in_reply, psci->name, namelen); + walklist = (xSyncSystemCounter *) (((char *) walklist) + + ((sz_xSyncSystemCounter + namelen + + 3) & ~3)); + } + + WriteToClient(client, sizeof(rep), (char *) &rep); + if (len) { + WriteToClient(client, len, (char *) list); + DEALLOCATE_LOCAL(list); + } + + return (client->noClientException); +} + +/* + * ** Set client Priority + */ +static int +ProcSyncSetPriority(client) +ClientPtr client; +{ + REQUEST(xSyncSetPriorityReq); + ClientPtr priorityclient; + + REQUEST_SIZE_MATCH(xSyncSetPriorityReq); + + if (stuff->id == None) + priorityclient = client; + else if (!(priorityclient = LookupClient(stuff->id, client))) { + client->errorValue = stuff->id; + return BadMatch; + } + + if (priorityclient->priority != stuff->priority) { + priorityclient->priority = stuff->priority; + + /* The following will force the server back into WaitForSomething + * so that the change in this client's priority is immediately + * reflected. + */ + isItTimeToYield = TRUE; + dispatchException |= DE_PRIORITYCHANGE; + } + return Success; +} + +/* + * ** Get client Priority + */ +static int +ProcSyncGetPriority(client) +ClientPtr client; +{ + REQUEST(xSyncGetPriorityReq); + xSyncGetPriorityReply rep; + + ClientPtr priorityclient; + + REQUEST_SIZE_MATCH(xSyncGetPriorityReq); + + if (stuff->id == None) + priorityclient = client; + else if (!(priorityclient = LookupClient(stuff->id, client))) { + client->errorValue = stuff->id; + return BadMatch; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.priority = priorityclient->priority; + + if (client->swapped) { + + swaps(&rep.sequenceNumber); + swapl(&rep.priority); + } + + WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep); + + return (client->noClientException); +} + +/* + * ** Create a new counter + */ +static int +ProcSyncCreateCounter(client) +ClientPtr client; +{ + REQUEST(xSyncCreateCounterReq); + CARD64 initial; + + REQUEST_SIZE_MATCH(xSyncCreateCounterReq); + + LEGAL_NEW_RESOURCE(stuff->cid, client); + + XSyncIntsToValue(&initial, stuff->initial_value_lo, + stuff->initial_value_hi); + if (!SyncCreateCounter(client, stuff->cid, initial)) + return BadAlloc; + + return (client->noClientException); +} + +/* + * ** Set Counter value + */ +static int +ProcSyncSetCounter(client) +ClientPtr client; +{ + REQUEST(xSyncSetCounterReq); + SyncCounter *pCounter; + + CARD64 newvalue; + + REQUEST_SIZE_MATCH(xSyncSetCounterReq); + + pCounter = (SyncCounter *) SecurityLookupIDByType(client, stuff->cid, + RTCounter, + SecurityWriteAccess); + if (pCounter == NULL) { + client->errorValue = stuff->cid; + return SyncErrorBase + XSyncBadCounter; + } + + if (IsSystemCounter(pCounter)) { + client->errorValue = stuff->cid; + return BadAccess; + } + + XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi); + SyncChangeCounter(pCounter, newvalue); + return Success; +} + +/* + * ** Change Counter value + */ +static int +ProcSyncChangeCounter(client) +ClientPtr client; +{ + REQUEST(xSyncChangeCounterReq); + SyncCounter *pCounter; + + CARD64 newvalue; + + Bool overflow; + + REQUEST_SIZE_MATCH(xSyncChangeCounterReq); + + pCounter = (SyncCounter *) SecurityLookupIDByType(client, stuff->cid, + RTCounter, + SecurityWriteAccess); + if (pCounter == NULL) { + client->errorValue = stuff->cid; + return SyncErrorBase + XSyncBadCounter; + } + + if (IsSystemCounter(pCounter)) { + client->errorValue = stuff->cid; + return BadAccess; + } + + XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi); + XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow); + if (overflow) { + /* XXX 64 bit value can't fit in 32 bits; do the best we can */ + client->errorValue = stuff->value_hi; + return BadValue; + } + SyncChangeCounter(pCounter, newvalue); + return Success; +} + +/* + * ** Destroy a counter + */ +static int +ProcSyncDestroyCounter(client) +ClientPtr client; +{ + REQUEST(xSyncDestroyCounterReq); + SyncCounter *pCounter; + + REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); + + pCounter = (SyncCounter *) SecurityLookupIDByType(client, stuff->counter, + RTCounter, + SecurityDestroyAccess); + if (pCounter == NULL) { + client->errorValue = stuff->counter; + return SyncErrorBase + XSyncBadCounter; + } + if (IsSystemCounter(pCounter)) { + client->errorValue = stuff->counter; + return BadAccess; + } + FreeResource(pCounter->id, RT_NONE); + return Success; +} + +/* + * ** Await + */ +static int +ProcSyncAwait(client) +ClientPtr client; +{ + REQUEST(xSyncAwaitReq); + int len, items; + + int i; + + xSyncWaitCondition *pProtocolWaitConds; + + SyncAwaitUnion *pAwaitUnion; + + SyncAwait *pAwait; + + int status; + + REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); + + len = client->req_len << 2; + len -= sz_xSyncAwaitReq; + items = len / sz_xSyncWaitCondition; + + if (items * sz_xSyncWaitCondition != len) { + return BadLength; + } + if (items == 0) { + client->errorValue = items; /* XXX protocol change */ + return BadValue; + } + + pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1]; + + /* all the memory for the entire await list is allocated + * here in one chunk + */ + pAwaitUnion = + malloc((items + 1) * sizeof(SyncAwaitUnion)); + if (!pAwaitUnion) + return BadAlloc; + + /* first item is the header, remainder are real wait conditions */ + + pAwaitUnion->header.delete_id = FakeClientID(client->index); + if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion)) { + free(pAwaitUnion); + return BadAlloc; + } + + /* don't need to do any more memory allocation for this request! */ + + pAwaitUnion->header.client = client; + pAwaitUnion->header.num_waitconditions = 0; + + pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ + for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++) { + if (pProtocolWaitConds->counter == None) { /* XXX protocol change */ + /* this should take care of removing any triggers created by + * this request that have already been registered on counters + */ + FreeResource(pAwaitUnion->header.delete_id, RT_NONE); + client->errorValue = pProtocolWaitConds->counter; + return SyncErrorBase + XSyncBadCounter; + } + + /* sanity checks are in SyncInitTrigger */ + pAwait->trigger.pCounter = NULL; + pAwait->trigger.value_type = pProtocolWaitConds->value_type; + XSyncIntsToValue(&pAwait->trigger.wait_value, + pProtocolWaitConds->wait_value_lo, + pProtocolWaitConds->wait_value_hi); + pAwait->trigger.test_type = pProtocolWaitConds->test_type; + + status = SyncInitTrigger(client, &pAwait->trigger, + pProtocolWaitConds->counter, + XSyncCAAllTrigger); + if (status != Success) { + /* this should take care of removing any triggers created by + * this request that have already been registered on counters + */ + FreeResource(pAwaitUnion->header.delete_id, RT_NONE); + return status; + } + /* this is not a mistake -- same function works for both cases */ + pAwait->trigger.TriggerFired = SyncAwaitTriggerFired; + pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired; + XSyncIntsToValue(&pAwait->event_threshold, + pProtocolWaitConds->event_threshold_lo, + pProtocolWaitConds->event_threshold_hi); + pAwait->pHeader = &pAwaitUnion->header; + pAwaitUnion->header.num_waitconditions++; + } + + IgnoreClient(client); + + /* see if any of the triggers are already true */ + + pAwait = &(pAwaitUnion + 1)->await; /* skip over header */ + for (i = 0; i < items; i++, pAwait++) { + /* don't have to worry about NULL counters because the request + * errors before we get here out if they occur + */ + if ((*pAwait->trigger.CheckTrigger) (&pAwait->trigger, + pAwait->trigger.pCounter->value)) { + (*pAwait->trigger.TriggerFired) (&pAwait->trigger); + break; /* once is enough */ + } + } + return Success; +} + +/* + * ** Query a counter + */ +static int +ProcSyncQueryCounter(client) +ClientPtr client; +{ + REQUEST(xSyncQueryCounterReq); + xSyncQueryCounterReply rep; + + SyncCounter *pCounter; + + REQUEST_SIZE_MATCH(xSyncQueryCounterReq); + + pCounter = (SyncCounter *) SecurityLookupIDByType(client, stuff->counter, + RTCounter, + SecurityReadAccess); + if (pCounter == NULL) { + client->errorValue = stuff->counter; + return SyncErrorBase + XSyncBadCounter; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + /* if system counter, ask it what the current value is */ + + if (IsSystemCounter(pCounter)) { + (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter, + &pCounter->value); + } + + rep.value_hi = XSyncValueHigh32(pCounter->value); + rep.value_lo = XSyncValueLow32(pCounter->value); + if (client->swapped) { + + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.value_hi); + swapl(&rep.value_lo); + } + WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep); + return (client->noClientException); +} + +/* + * ** Create Alarm + */ +static int +ProcSyncCreateAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncCreateAlarmReq); + SyncAlarm *pAlarm; + + int status; + + unsigned long len, vmask; + + SyncTrigger *pTrigger; + + REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); + + LEGAL_NEW_RESOURCE(stuff->id, client); + + vmask = stuff->valueMask; + len = client->req_len - (sizeof(xSyncCreateAlarmReq) >> 2); + /* the "extra" call to Ones accounts for the presence of 64 bit values */ + if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) + return BadLength; + + if (!(pAlarm = malloc(sizeof(SyncAlarm)))) { + return BadAlloc; + } + + /* set up defaults */ + + pTrigger = &pAlarm->trigger; + pTrigger->pCounter = NULL; + pTrigger->value_type = XSyncAbsolute; + XSyncIntToValue(&pTrigger->wait_value, 0L); + pTrigger->test_type = XSyncPositiveComparison; + pTrigger->TriggerFired = SyncAlarmTriggerFired; + pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed; + status = SyncInitTrigger(client, pTrigger, None, XSyncCAAllTrigger); + if (status != Success) { + free(pAlarm); + return status; + } + + pAlarm->client = client; + pAlarm->alarm_id = stuff->id; + XSyncIntToValue(&pAlarm->delta, 1L); + pAlarm->events = TRUE; + pAlarm->state = XSyncAlarmInactive; + pAlarm->pEventClients = NULL; + status = SyncChangeAlarmAttributes(client, pAlarm, vmask, + (CARD32 *) &stuff[1]); + if (status != Success) { + free(pAlarm); + return status; + } + + if (!AddResource(stuff->id, RTAlarm, pAlarm)) { + free(pAlarm); + return BadAlloc; + } + + /* see if alarm already triggered. NULL counter will not trigger + * in CreateAlarm and sets alarm state to Inactive. + */ + + if (!pTrigger->pCounter) { + pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */ + } + else if ((*pTrigger->CheckTrigger) (pTrigger, pTrigger->pCounter->value)) { + (*pTrigger->TriggerFired) (pTrigger); + } + + return Success; +} + +/* + * ** Change Alarm + */ +static int +ProcSyncChangeAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncChangeAlarmReq); + SyncAlarm *pAlarm; + + long vmask; + + int len, status; + + REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); + + if (!(pAlarm = (SyncAlarm *) SecurityLookupIDByType(client, stuff->alarm, + RTAlarm, + SecurityWriteAccess))) { + client->errorValue = stuff->alarm; + return SyncErrorBase + XSyncBadAlarm; + } + + vmask = stuff->valueMask; + len = client->req_len - (sizeof(xSyncChangeAlarmReq) >> 2); + /* the "extra" call to Ones accounts for the presence of 64 bit values */ + if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue | XSyncCADelta)))) + return BadLength; + + if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask, + (CARD32 *) &stuff[1])) != Success) + return status; + + /* see if alarm already triggered. NULL counter WILL trigger + * in ChangeAlarm. + */ + + if (!pAlarm->trigger.pCounter || + (*pAlarm->trigger.CheckTrigger) (&pAlarm->trigger, + pAlarm->trigger.pCounter->value)) { + (*pAlarm->trigger.TriggerFired) (&pAlarm->trigger); + } + return Success; +} + +static int +ProcSyncQueryAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncQueryAlarmReq); + SyncAlarm *pAlarm; + + xSyncQueryAlarmReply rep; + + SyncTrigger *pTrigger; + + REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); + + pAlarm = (SyncAlarm *) SecurityLookupIDByType(client, stuff->alarm, + RTAlarm, SecurityReadAccess); + if (!pAlarm) { + client->errorValue = stuff->alarm; + return (SyncErrorBase + XSyncBadAlarm); + } + + rep.type = X_Reply; + rep.length = (sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply)) >> 2; + rep.sequenceNumber = client->sequence; + + pTrigger = &pAlarm->trigger; + rep.counter = (pTrigger->pCounter) ? pTrigger->pCounter->id : None; + +#if 0 /* XXX unclear what to do, depends on whether relative value-types + * are "consumed" immediately and are considered absolute from then + * on. + */ + rep.value_type = pTrigger->value_type; + rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value); + rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value); +#else + rep.value_type = XSyncAbsolute; + rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value); + rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value); +#endif + + rep.test_type = pTrigger->test_type; + rep.delta_hi = XSyncValueHigh32(pAlarm->delta); + rep.delta_lo = XSyncValueLow32(pAlarm->delta); + rep.events = pAlarm->events; + rep.state = pAlarm->state; + + if (client->swapped) { + + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.counter); + swapl(&rep.wait_value_hi); + swapl(&rep.wait_value_lo); + swapl(&rep.test_type); + swapl(&rep.delta_hi); + swapl(&rep.delta_lo); + } + + WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcSyncDestroyAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncDestroyAlarmReq); + + REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); + + if (!((SyncAlarm *) SecurityLookupIDByType(client, stuff->alarm, + RTAlarm, SecurityDestroyAccess))) + { + client->errorValue = stuff->alarm; + return SyncErrorBase + XSyncBadAlarm; + } + + FreeResource(stuff->alarm, RT_NONE); + return (client->noClientException); +} + +/* + * ** Given an extension request, call the appropriate request procedure + */ +static int +ProcSyncDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + + switch (stuff->data) { + + case X_SyncInitialize: + return ProcSyncInitialize(client); + case X_SyncListSystemCounters: + return ProcSyncListSystemCounters(client); + case X_SyncCreateCounter: + return ProcSyncCreateCounter(client); + case X_SyncSetCounter: + return ProcSyncSetCounter(client); + case X_SyncChangeCounter: + return ProcSyncChangeCounter(client); + case X_SyncQueryCounter: + return ProcSyncQueryCounter(client); + case X_SyncDestroyCounter: + return ProcSyncDestroyCounter(client); + case X_SyncAwait: + return ProcSyncAwait(client); + case X_SyncCreateAlarm: + return ProcSyncCreateAlarm(client); + case X_SyncChangeAlarm: + return ProcSyncChangeAlarm(client); + case X_SyncQueryAlarm: + return ProcSyncQueryAlarm(client); + case X_SyncDestroyAlarm: + return ProcSyncDestroyAlarm(client); + case X_SyncSetPriority: + return ProcSyncSetPriority(client); + case X_SyncGetPriority: + return ProcSyncGetPriority(client); + default: + return BadRequest; + } +} + +/* + * Boring Swapping stuff ... + */ + +static int +SProcSyncInitialize(client) +ClientPtr client; +{ + REQUEST(xSyncInitializeReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncInitializeReq); + + return ProcSyncInitialize(client); +} + +static int +SProcSyncListSystemCounters(client) +ClientPtr client; +{ + REQUEST(xSyncListSystemCountersReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncListSystemCountersReq); + + return ProcSyncListSystemCounters(client); +} + +static int +SProcSyncCreateCounter(client) +ClientPtr client; +{ + REQUEST(xSyncCreateCounterReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncCreateCounterReq); + swapl(&stuff->cid); + swapl(&stuff->initial_value_lo); + swapl(&stuff->initial_value_hi); + + return ProcSyncCreateCounter(client); +} + +static int +SProcSyncSetCounter(client) +ClientPtr client; +{ + REQUEST(xSyncSetCounterReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncSetCounterReq); + swapl(&stuff->cid); + swapl(&stuff->value_lo); + swapl(&stuff->value_hi); + + return ProcSyncSetCounter(client); +} + +static int +SProcSyncChangeCounter(client) +ClientPtr client; +{ + REQUEST(xSyncChangeCounterReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncChangeCounterReq); + swapl(&stuff->cid); + swapl(&stuff->value_lo); + swapl(&stuff->value_hi); + + return ProcSyncChangeCounter(client); +} + +static int +SProcSyncQueryCounter(client) +ClientPtr client; +{ + REQUEST(xSyncQueryCounterReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncQueryCounterReq); + swapl(&stuff->counter); + + return ProcSyncQueryCounter(client); +} + +static int +SProcSyncDestroyCounter(client) +ClientPtr client; +{ + REQUEST(xSyncDestroyCounterReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncDestroyCounterReq); + swapl(&stuff->counter); + + return ProcSyncDestroyCounter(client); +} + +static int +SProcSyncAwait(client) +ClientPtr client; +{ + REQUEST(xSyncAwaitReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xSyncAwaitReq); + SwapRestL(stuff); + + return ProcSyncAwait(client); +} + +static int +SProcSyncCreateAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncCreateAlarmReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq); + swapl(&stuff->id); + swapl(&stuff->valueMask); + SwapRestL(stuff); + + return ProcSyncCreateAlarm(client); +} + +static int +SProcSyncChangeAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncChangeAlarmReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq); + swapl(&stuff->alarm); + swapl(&stuff->valueMask); + SwapRestL(stuff); + return ProcSyncChangeAlarm(client); +} + +static int +SProcSyncQueryAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncQueryAlarmReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncQueryAlarmReq); + swapl(&stuff->alarm); + + return ProcSyncQueryAlarm(client); +} + +static int +SProcSyncDestroyAlarm(client) +ClientPtr client; +{ + REQUEST(xSyncDestroyAlarmReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq); + swapl(&stuff->alarm); + + return ProcSyncDestroyAlarm(client); +} + +static int +SProcSyncSetPriority(client) +ClientPtr client; +{ + REQUEST(xSyncSetPriorityReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncSetPriorityReq); + swapl(&stuff->id); + swapl(&stuff->priority); + + return ProcSyncSetPriority(client); +} + +static int +SProcSyncGetPriority(client) +ClientPtr client; +{ + REQUEST(xSyncGetPriorityReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xSyncGetPriorityReq); + swapl(&stuff->id); + + return ProcSyncGetPriority(client); +} + +static int +SProcSyncDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_SyncInitialize: + return SProcSyncInitialize(client); + case X_SyncListSystemCounters: + return SProcSyncListSystemCounters(client); + case X_SyncCreateCounter: + return SProcSyncCreateCounter(client); + case X_SyncSetCounter: + return SProcSyncSetCounter(client); + case X_SyncChangeCounter: + return SProcSyncChangeCounter(client); + case X_SyncQueryCounter: + return SProcSyncQueryCounter(client); + case X_SyncDestroyCounter: + return SProcSyncDestroyCounter(client); + case X_SyncAwait: + return SProcSyncAwait(client); + case X_SyncCreateAlarm: + return SProcSyncCreateAlarm(client); + case X_SyncChangeAlarm: + return SProcSyncChangeAlarm(client); + case X_SyncQueryAlarm: + return SProcSyncQueryAlarm(client); + case X_SyncDestroyAlarm: + return SProcSyncDestroyAlarm(client); + case X_SyncSetPriority: + return SProcSyncSetPriority(client); + case X_SyncGetPriority: + return SProcSyncGetPriority(client); + default: + return BadRequest; + } +} + +/* + * Event Swapping + */ + +static void +SCounterNotifyEvent(from, to) +xSyncCounterNotifyEvent *from, *to; +{ + to->type = from->type; + to->kind = from->kind; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->counter, to->counter); + cpswapl(from->wait_value_lo, to->wait_value_lo); + cpswapl(from->wait_value_hi, to->wait_value_hi); + cpswapl(from->counter_value_lo, to->counter_value_lo); + cpswapl(from->counter_value_hi, to->counter_value_hi); + cpswapl(from->time, to->time); + cpswaps(from->count, to->count); + to->destroyed = from->destroyed; +} + +static void +SAlarmNotifyEvent(from, to) +xSyncAlarmNotifyEvent *from, *to; +{ + to->type = from->type; + to->kind = from->kind; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->alarm, to->alarm); + cpswapl(from->counter_value_lo, to->counter_value_lo); + cpswapl(from->counter_value_hi, to->counter_value_hi); + cpswapl(from->alarm_value_lo, to->alarm_value_lo); + cpswapl(from->alarm_value_hi, to->alarm_value_hi); + cpswapl(from->time, to->time); + to->state = from->state; +} + +/* + * ** Close everything down. ** This is fairly simple for now. + */ +/* ARGSUSED */ +static void +SyncResetProc(extEntry) +ExtensionEntry *extEntry; +{ + free(SysCounterList); + SysCounterList = NULL; + RTCounter = 0; +} + +/* + * ** Initialise the extension. + */ +void +SyncExtensionInit(INITARGS) +{ + ExtensionEntry *extEntry; + + if (RTCounter == 0) { + RTCounter = CreateNewResourceType(FreeCounter); + } + RTAlarm = CreateNewResourceType(FreeAlarm); + RTAwait = CreateNewResourceType(FreeAwait) | RC_NEVERRETAIN; + RTAlarmClient = CreateNewResourceType(FreeAlarmClient) | RC_NEVERRETAIN; + + if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 || + RTAlarmClient == 0 || + (extEntry = AddExtension(SYNC_NAME, + XSyncNumberEvents, XSyncNumberErrors, + ProcSyncDispatch, SProcSyncDispatch, + SyncResetProc, StandardMinorOpcode)) == NULL) { + ErrorF("Sync Extension %d.%d failed to Initialise\n", + SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); + return; + } + + SyncEventBase = extEntry->eventBase; + SyncErrorBase = extEntry->errorBase; + EventSwapVector[SyncEventBase + XSyncCounterNotify] = + (EventSwapPtr) SCounterNotifyEvent; + EventSwapVector[SyncEventBase + XSyncAlarmNotify] = + (EventSwapPtr) SAlarmNotifyEvent; + + /* + * Although SERVERTIME is implemented by the OS layer, we initialise it + * here because doing it in OsInit() is too early. The resource database + * is not initialised when OsInit() is called. This is just about OK + * because there is always a servertime counter. + */ + SyncInitServerTime(); + +#ifdef DEBUG + fprintf(stderr, "Sync Extension %d.%d\n", + SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION); +#endif +} + +/* + * ***** SERVERTIME implementation - should go in its own file in OS directory? + */ + +static pointer ServertimeCounter; + +static XSyncValue Now; + +static XSyncValue *pnext_time; + +#define GetTime()\ +{\ + unsigned long millis = GetTimeInMillis();\ + unsigned long maxis = XSyncValueHigh32(Now);\ + if (millis < XSyncValueLow32(Now)) maxis++;\ + XSyncIntsToValue(&Now, millis, maxis);\ +} + +/* +*** Server Block Handler +*** code inspired by multibuffer extension + */ + /*ARGSUSED*/ static void +ServertimeBlockHandler(env, wt, LastSelectMask) +pointer env; + +struct timeval **wt; + +pointer LastSelectMask; +{ + XSyncValue delay; + + unsigned long timeout; + + if (pnext_time) { + GetTime(); + + if (XSyncValueGreaterOrEqual(Now, *pnext_time)) { + timeout = 0; + } + else { + Bool overflow; + + XSyncValueSubtract(&delay, *pnext_time, Now, &overflow); + (void) overflow; + timeout = XSyncValueLow32(delay); + } + AdjustWaitForDelay(wt, timeout); /* os/utils.c */ + } +} + +/* +*** Wakeup Handler + */ + /*ARGSUSED*/ static void +ServertimeWakeupHandler(env, rc, LastSelectMask) +pointer env; + +int rc; + +pointer LastSelectMask; +{ + if (pnext_time) { + GetTime(); + + if (XSyncValueGreaterOrEqual(Now, *pnext_time)) { + SyncChangeCounter(ServertimeCounter, Now); + } + } +} + +static void +ServertimeQueryValue(pCounter, pValue_return) +pointer pCounter; + +CARD64 *pValue_return; +{ + GetTime(); + *pValue_return = Now; +} + +static void +ServertimeBracketValues(pCounter, pbracket_less, pbracket_greater) +pointer pCounter; + +CARD64 *pbracket_less; + +CARD64 *pbracket_greater; +{ + if (!pnext_time && pbracket_greater) { + RegisterBlockAndWakeupHandlers(ServertimeBlockHandler, + ServertimeWakeupHandler, NULL); + } + else if (pnext_time && !pbracket_greater) { + RemoveBlockAndWakeupHandlers(ServertimeBlockHandler, + ServertimeWakeupHandler, NULL); + } + pnext_time = pbracket_greater; +} + +static void +SyncInitServerTime() +{ + CARD64 resolution; + + XSyncIntsToValue(&Now, GetTimeInMillis(), 0); + XSyncIntToValue(&resolution, 4); + ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution, + XSyncCounterNeverDecreases, + ServertimeQueryValue, + ServertimeBracketValues); + pnext_time = NULL; +} diff --git a/Xext/xcmisc.c b/Xext/xcmisc.c new file mode 100644 index 0000000..d8bfc81 --- /dev/null +++ b/Xext/xcmisc.c @@ -0,0 +1,244 @@ +/* + +Copyright 1993, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "swaprep.h" +#include +#include "extinit.h" + +#if 0 +static unsigned char XCMiscCode; +#endif + +static void XCMiscResetProc(ExtensionEntry * /* extEntry */ + ); + +static DISPATCH_PROC(ProcXCMiscDispatch); + +static DISPATCH_PROC(ProcXCMiscGetVersion); + +static DISPATCH_PROC(ProcXCMiscGetXIDList); + +static DISPATCH_PROC(ProcXCMiscGetXIDRange); + +static DISPATCH_PROC(SProcXCMiscDispatch); + +static DISPATCH_PROC(SProcXCMiscGetVersion); + +static DISPATCH_PROC(SProcXCMiscGetXIDList); + +static DISPATCH_PROC(SProcXCMiscGetXIDRange); + +void +XCMiscExtensionInit(INITARGS) +{ +#if 0 + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(XCMiscExtensionName, 0, 0, + ProcXCMiscDispatch, SProcXCMiscDispatch, + XCMiscResetProc, StandardMinorOpcode)) != 0) + XCMiscCode = (unsigned char) extEntry->base; +#else + (void) AddExtension(XCMiscExtensionName, 0, 0, + ProcXCMiscDispatch, SProcXCMiscDispatch, + XCMiscResetProc, StandardMinorOpcode); +#endif + + DeclareExtensionSecurity(XCMiscExtensionName, TRUE); +} + + /*ARGSUSED*/ static void +XCMiscResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static int +ProcXCMiscGetVersion(client) +ClientPtr client; +{ + xXCMiscGetVersionReply rep; + + + REQUEST_SIZE_MATCH(xXCMiscGetVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = XCMiscMajorVersion; + rep.minorVersion = XCMiscMinorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swaps(&rep.majorVersion); + swaps(&rep.minorVersion); + } + WriteToClient(client, sizeof(xXCMiscGetVersionReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcXCMiscGetXIDRange(client) +ClientPtr client; +{ + xXCMiscGetXIDRangeReply rep; + + + XID min_id, max_id; + + REQUEST_SIZE_MATCH(xXCMiscGetXIDRangeReq); + GetXIDRange(client->index, FALSE, &min_id, &max_id); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.start_id = min_id; + rep.count = max_id - min_id + 1; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.start_id); + swapl(&rep.count); + } + WriteToClient(client, sizeof(xXCMiscGetXIDRangeReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcXCMiscGetXIDList(client) +ClientPtr client; +{ + REQUEST(xXCMiscGetXIDListReq); + xXCMiscGetXIDListReply rep; + + + XID *pids; + + unsigned int count; + + REQUEST_SIZE_MATCH(xXCMiscGetXIDListReq); + + pids = (XID *) ALLOCATE_LOCAL(stuff->count * sizeof(XID)); + if (!pids) { + return BadAlloc; + } + count = GetXIDList(client, stuff->count, pids); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = count; + rep.count = count; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.count); + } + WriteToClient(client, sizeof(xXCMiscGetXIDListReply), (char *) &rep); + if (count) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, count * sizeof(XID), pids); + } + DEALLOCATE_LOCAL(pids); + return (client->noClientException); +} + +static int +ProcXCMiscDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XCMiscGetVersion: + return ProcXCMiscGetVersion(client); + case X_XCMiscGetXIDRange: + return ProcXCMiscGetXIDRange(client); + case X_XCMiscGetXIDList: + return ProcXCMiscGetXIDList(client); + default: + return BadRequest; + } +} + +static int +SProcXCMiscGetVersion(client) +ClientPtr client; +{ + + REQUEST(xXCMiscGetVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xXCMiscGetVersionReq); + swaps(&stuff->majorVersion); + swaps(&stuff->minorVersion); + return ProcXCMiscGetVersion(client); +} + +static int +SProcXCMiscGetXIDRange(client) +ClientPtr client; +{ + + REQUEST(xReq); + + swaps(&stuff->length); + return ProcXCMiscGetXIDRange(client); +} + +static int +SProcXCMiscGetXIDList(client) +ClientPtr client; +{ + + REQUEST(xXCMiscGetXIDListReq); + + swaps(&stuff->length); + swapl(&stuff->count); + return ProcXCMiscGetXIDList(client); +} + +static int +SProcXCMiscDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XCMiscGetVersion: + return SProcXCMiscGetVersion(client); + case X_XCMiscGetXIDRange: + return SProcXCMiscGetXIDRange(client); + case X_XCMiscGetXIDList: + return SProcXCMiscGetXIDList(client); + default: + return BadRequest; + } +} diff --git a/Xext/xf86bigfont.c b/Xext/xf86bigfont.c new file mode 100644 index 0000000..c3a04f3 --- /dev/null +++ b/Xext/xf86bigfont.c @@ -0,0 +1,779 @@ +/* + * BIGFONT extension for sharing font metrics between clients (if possible) + * and for transmitting font metrics to clients in a compressed form. + * + * Copyright (c) 1999-2000 Bruno Haible + * Copyright (c) 1999-2000 The XFree86 Project, Inc. + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +/* + * Big fonts suffer from the following: All clients that have opened a + * font can access the complete glyph metrics array (the XFontStruct member + * `per_char') directly, without going through a macro. Moreover these + * glyph metrics are ink metrics, i.e. are not redundant even for a + * fixed-width font. For a Unicode font, the size of this array is 768 KB. + * + * Problems: 1. It eats a lot of memory in each client. 2. All this glyph + * metrics data is piped through the socket when the font is opened. + * + * This extension addresses these two problems for local clients, by using + * shared memory. It also addresses the second problem for non-local clients, + * by compressing the data before transmit by a factor of nearly 6. + * + * If you use this extension, your OS ought to nicely support shared memory. + * This means: Shared memory should be swappable to the swap, and the limits + * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB, + * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls + * on segments that have already been marked "removed", because it permits + * these segments to be cleaned up by the OS if the X server is killed with + * signal SIGKILL. + * + * This extension is transparently exploited by Xlib (functions XQueryFont, + * XLoadQueryFont). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2) +/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */ +/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers): + Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define + PAGE_SIZE. It is defined in . */ +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "dixfontstr.h" +#include "extnsionst.h" + +#define _XF86BIGFONT_SERVER_ +#include + +static void XF86BigfontResetProc(ExtensionEntry * /* extEntry */ + ); + +static DISPATCH_PROC(ProcXF86BigfontDispatch); + +static DISPATCH_PROC(ProcXF86BigfontQueryVersion); + +static DISPATCH_PROC(ProcXF86BigfontQueryFont); + +static DISPATCH_PROC(SProcXF86BigfontDispatch); + +static DISPATCH_PROC(SProcXF86BigfontQueryVersion); + +static DISPATCH_PROC(SProcXF86BigfontQueryFont); + +#if 0 +static unsigned char XF86BigfontReqCode; +#endif + + +/* A random signature, transmitted to the clients so they can verify that the + shared memory segment they are attaching to was really established by the + X server they are talking to. */ +static CARD32 signature; + +/* Index for additional information stored in a FontRec's devPrivates array. */ +static int FontShmdescIndex; + +static unsigned int pagesize; + +static Bool badSysCall = FALSE; + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) + +#include + +static void +SigSysHandler(int signo) +{ + badSysCall = TRUE; +} + +static Bool +CheckForShmSyscall(void) +{ + void (*oldHandler) (int); + + int shmid = -1; + + /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ + oldHandler = signal(SIGSYS, SigSysHandler); + + badSysCall = FALSE; + shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); + if (shmid != -1) { + /* Successful allocation - clean up */ + shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL); + } + else { + /* Allocation failed */ + badSysCall = TRUE; + } + signal(SIGSYS, oldHandler); + return (!badSysCall); +} + +#define MUST_CHECK_FOR_SHM_SYSCALL + +#endif + + +void +XFree86BigfontExtensionInit() +{ +#if 0 + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(XF86BIGFONTNAME, + XF86BigfontNumberEvents, + XF86BigfontNumberErrors, + ProcXF86BigfontDispatch, + SProcXF86BigfontDispatch, + XF86BigfontResetProc, StandardMinorOpcode))) { + XF86BigfontReqCode = (unsigned char) extEntry->base; +#else + if (AddExtension(XF86BIGFONTNAME, + XF86BigfontNumberEvents, + XF86BigfontNumberErrors, + ProcXF86BigfontDispatch, + SProcXF86BigfontDispatch, + XF86BigfontResetProc, StandardMinorOpcode)) { +#endif +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + /* + * Note: Local-clients will not be optimized without shared memory + * support. Remote-client optimization does not depend on shared + * memory support. Thus, the extension is still registered even + * when shared memory support is not functional. + */ + if (!CheckForShmSyscall()) { + ErrorF(XF86BIGFONTNAME + " extension local-client optimization disabled due to lack of shared memory support in the kernel\n"); + return; + } +#endif + + srand((unsigned int) time(NULL)); + signature = ((unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand()) << 16) + + (unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand()); + /* fprintf(stderr, "signature = 0x%08X\n", signature); */ + + FontShmdescIndex = AllocateFontPrivateIndex(); + +#if !defined(CSRG_BASED) && !defined(__CYGWIN__) + pagesize = SHMLBA; +#else +# ifdef _SC_PAGESIZE + pagesize = sysconf(_SC_PAGESIZE); +# else + pagesize = getpagesize(); +# endif +#endif + } +} + +/* ========== Management of shared memory segments ========== */ + + +#ifdef __linux__ +/* On Linux, shared memory marked as "removed" can still be attached. + Nice feature, because the kernel will automatically free the associated + storage when the server and all clients are gone. */ +#define EARLY_REMOVE +#endif + +typedef struct _ShmDesc { + struct _ShmDesc *next; + struct _ShmDesc **prev; + int shmid; + char *attach_addr; +} ShmDescRec, *ShmDescPtr; + +static ShmDescPtr ShmList = (ShmDescPtr) NULL; + +static ShmDescPtr +shmalloc(unsigned int size) +{ + ShmDescPtr pDesc; + + int shmid; + + char *addr; + +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + if (pagesize == 0) + return (ShmDescPtr) NULL; +#endif + + /* On some older Linux systems, the number of shared memory segments + system-wide is 127. In Linux 2.4, it is 4095. + Therefore there is a tradeoff to be made between allocating a + shared memory segment on one hand, and allocating memory and piping + the glyph metrics on the other hand. If the glyph metrics size is + small, we prefer the traditional way. */ + if (size < 3500) + return (ShmDescPtr) NULL; + + pDesc = malloc(sizeof(ShmDescRec)); + if (!pDesc) + return (ShmDescPtr) NULL; + + size = (size + pagesize - 1) & -pagesize; + shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + if (shmid == -1) { + ErrorF(XF86BIGFONTNAME + " extension: shmget() failed, size = %u, errno = %d\n", size, + errno); + free(pDesc); + return (ShmDescPtr) NULL; + } + + if ((addr = shmat(shmid, 0, 0)) == (char *) -1) { + ErrorF(XF86BIGFONTNAME + " extension: shmat() failed, size = %u, errno = %d\n", size, + errno); + shmctl(shmid, IPC_RMID, (void *) 0); + free(pDesc); + return (ShmDescPtr) NULL; + } + +#ifdef EARLY_REMOVE + shmctl(shmid, IPC_RMID, (void *) 0); +#endif + + pDesc->shmid = shmid; + pDesc->attach_addr = addr; + if (ShmList) + ShmList->prev = &pDesc->next; + pDesc->next = ShmList; + pDesc->prev = &ShmList; + ShmList = pDesc; + + return pDesc; +} + +static void +shmdealloc(ShmDescPtr pDesc) +{ +#ifndef EARLY_REMOVE + shmctl(pDesc->shmid, IPC_RMID, (void *) 0); +#endif + shmdt(pDesc->attach_addr); + + if (pDesc->next) + pDesc->next->prev = pDesc->prev; + *pDesc->prev = pDesc->next; + free(pDesc); +} + + +/* Called when a font is closed. */ +void +XF86BigfontFreeFontShm(FontPtr pFont) +{ + ShmDescPtr pDesc; + + /* If during shutdown of the server, XF86BigfontCleanup() has already + * called shmdealloc() for all segments, we don't need to do it here. + */ + if (!ShmList) + return; + + pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); + if (pDesc) + shmdealloc(pDesc); +} + +/* Called upon fatal signal. */ +void +XF86BigfontCleanup() +{ + while (ShmList) + shmdealloc(ShmList); +} + +/* Called when a server generation dies. */ +static void +XF86BigfontResetProc(ExtensionEntry * extEntry) +{ + /* This function is normally called from CloseDownExtensions(), called + * from main(). It will be followed by a call to FreeAllResources(), + * which will call XF86BigfontFreeFontShm() for each font. Thus it + * appears that we do not need to do anything in this function. -- + * But I prefer to write robust code, and not keep shared memory lying + * around when it's not needed any more. (Someone might close down the + * extension without calling FreeAllResources()...) + */ + XF86BigfontCleanup(); +} + +/* ========== Handling of extension specific requests ========== */ + +static int +ProcXF86BigfontQueryVersion(ClientPtr client) +{ + xXF86BigfontQueryVersionReply reply = {0}; + + REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.majorVersion = XF86BIGFONT_MAJOR_VERSION; + reply.minorVersion = XF86BIGFONT_MINOR_VERSION; + reply.uid = geteuid(); + reply.gid = getegid(); + reply.signature = signature; + reply.capabilities = + (LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0) + ; /* may add more bits here in future versions */ + if (client->swapped) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swaps(&reply.majorVersion); + swaps(&reply.minorVersion); + swapl(&reply.uid); + swapl(&reply.gid); + swapl(&reply.signature); + } + WriteToClient(client, + sizeof(xXF86BigfontQueryVersionReply), (char *) &reply); + return client->noClientException; +} + +static void +swapCharInfo(xCharInfo * pCI) +{ + swaps(&pCI->leftSideBearing); + swaps(&pCI->rightSideBearing); + swaps(&pCI->characterWidth); + swaps(&pCI->ascent); + swaps(&pCI->descent); + swaps(&pCI->attributes); +} + +/* static CARD32 hashCI (xCharInfo *p); */ +#define hashCI(p) \ + (CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \ + (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \ + (p->characterWidth << 16) + \ + (p->ascent << 11) + (p->descent << 6)) ^ p->attributes) + +static int +ProcXF86BigfontQueryFont(ClientPtr client) +{ + FontPtr pFont; + + REQUEST(xXF86BigfontQueryFontReq); + CARD32 stuff_flags; + + xCharInfo *pmax; + + xCharInfo *pmin; + + int nCharInfos; + + int shmid; + + ShmDescPtr pDesc; + xCharInfo *pCI; + + CARD16 *pIndex2UniqIndex; + + CARD16 *pUniqIndex2Index; + + CARD32 nUniqCharInfos; + +#if 0 + REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); +#else + switch (client->req_len) { + case 2: /* client with version 1.0 libX11 */ + stuff_flags = (LocalClient(client) && + !client->swapped ? XF86Bigfont_FLAGS_Shm : 0); + break; + case 3: /* client with version 1.1 libX11 */ + stuff_flags = stuff->flags; + break; + default: + return BadLength; + } +#endif + client->errorValue = stuff->id; /* EITHER font or gc */ + pFont = (FontPtr) SecurityLookupIDByType(client, stuff->id, RT_FONT, + SecurityReadAccess); + if (!pFont) { + /* can't use VERIFY_GC because it might return BadGC */ + GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC, + SecurityReadAccess); + + if (!pGC) { + client->errorValue = stuff->id; + return BadFont; /* procotol spec says only error is BadFont */ + } + pFont = pGC->font; + } + + pmax = FONTINKMAX(pFont); + pmin = FONTINKMIN(pFont); + nCharInfos = + (pmax->rightSideBearing == pmin->rightSideBearing + && pmax->leftSideBearing == pmin->leftSideBearing + && pmax->descent == pmin->descent + && pmax->ascent == pmin->ascent + && pmax->characterWidth == pmin->characterWidth) + ? 0 : N2dChars(pFont); + shmid = -1; + pCI = NULL; + pIndex2UniqIndex = NULL; + pUniqIndex2Index = NULL; + nUniqCharInfos = 0; + + if (nCharInfos > 0) { + if (!badSysCall) + pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); + else + pDesc = NULL; + if (pDesc) { + pCI = (xCharInfo *) pDesc->attach_addr; + if (stuff_flags & XF86Bigfont_FLAGS_Shm) + shmid = pDesc->shmid; + } + else { + if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall) + pDesc = shmalloc(nCharInfos * sizeof(xCharInfo) + + sizeof(CARD32)); + if (pDesc) { + pCI = (xCharInfo *) pDesc->attach_addr; + shmid = pDesc->shmid; + } + else { + pCI = (xCharInfo *) + ALLOCATE_LOCAL(nCharInfos * sizeof(xCharInfo)); + if (!pCI) + return BadAlloc; + } + /* Fill nCharInfos starting at pCI. */ + { + xCharInfo *prCI = pCI; + + int ninfos = 0; + + int ncols = pFont->info.lastCol - pFont->info.firstCol + 1; + + int row; + + for (row = pFont->info.firstRow; + row <= pFont->info.lastRow && ninfos < nCharInfos; row++) { + unsigned char chars[512]; + + xCharInfo *tmpCharInfos[256]; + + unsigned long count; + + int col; + + unsigned long i; + + i = 0; + for (col = pFont->info.firstCol; + col <= pFont->info.lastCol; col++) { + chars[i++] = row; + chars[i++] = col; + } + (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit, + &count, tmpCharInfos); + for (i = 0; i < count && ninfos < nCharInfos; i++) { + *prCI++ = *tmpCharInfos[i]; + ninfos++; + } + } + } + if (pDesc && !badSysCall) { + *(CARD32 *) (pCI + nCharInfos) = signature; + if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) { + shmdealloc(pDesc); + return BadAlloc; + } + } + } + if (shmid == -1) { + /* Cannot use shared memory, so remove-duplicates the xCharInfos + using a temporary hash table. */ + /* Note that CARD16 is suitable as index type, because + nCharInfos <= 0x10000. */ + CARD32 hashModulus; + + CARD16 *pHash2UniqIndex; + + CARD16 *pUniqIndex2NextUniqIndex; + + CARD32 NextIndex; + + CARD32 NextUniqIndex; + + CARD16 *tmp; + + CARD32 i, j; + + hashModulus = 67; + if (hashModulus > nCharInfos + 1) + hashModulus = nCharInfos + 1; + + tmp = (CARD16 *) + ALLOCATE_LOCAL((4 * nCharInfos + 1) * sizeof(CARD16)); + if (!tmp) { + if (!pDesc) + DEALLOCATE_LOCAL(pCI); + return BadAlloc; + } + pIndex2UniqIndex = tmp; + /* nCharInfos elements */ + pUniqIndex2Index = tmp + nCharInfos; + /* max. nCharInfos elements */ + pUniqIndex2NextUniqIndex = tmp + 2 * nCharInfos; + /* max. nCharInfos elements */ + pHash2UniqIndex = tmp + 3 * nCharInfos; + /* hashModulus (<= nCharInfos+1) elements */ + + /* Note that we can use 0xffff as end-of-list indicator, because + even if nCharInfos = 0x10000, 0xffff can not occur as valid + entry before the last element has been inserted. And once the + last element has been inserted, we don't need the hash table + any more. */ + for (j = 0; j < hashModulus; j++) + pHash2UniqIndex[j] = (CARD16) (-1); + + NextUniqIndex = 0; + for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) { + xCharInfo *p = &pCI[NextIndex]; + + CARD32 hashCode = hashCI(p) % hashModulus; + + for (i = pHash2UniqIndex[hashCode]; + i != (CARD16) (-1); i = pUniqIndex2NextUniqIndex[i]) { + j = pUniqIndex2Index[i]; + if (pCI[j].leftSideBearing == p->leftSideBearing + && pCI[j].rightSideBearing == p->rightSideBearing + && pCI[j].characterWidth == p->characterWidth + && pCI[j].ascent == p->ascent + && pCI[j].descent == p->descent + && pCI[j].attributes == p->attributes) + break; + } + if (i != (CARD16) (-1)) { + /* Found *p at Index j, UniqIndex i */ + pIndex2UniqIndex[NextIndex] = i; + } + else { + /* Allocate a new entry in the Uniq table */ + if (hashModulus <= 2 * NextUniqIndex + && hashModulus < nCharInfos + 1) { + /* Time to increate hash table size */ + hashModulus = 2 * hashModulus + 1; + if (hashModulus > nCharInfos + 1) + hashModulus = nCharInfos + 1; + for (j = 0; j < hashModulus; j++) + pHash2UniqIndex[j] = (CARD16) (-1); + for (i = 0; i < NextUniqIndex; i++) + pUniqIndex2NextUniqIndex[i] = (CARD16) (-1); + for (i = 0; i < NextUniqIndex; i++) { + j = pUniqIndex2Index[i]; + p = &pCI[j]; + hashCode = hashCI(p) % hashModulus; + pUniqIndex2NextUniqIndex[i] = + pHash2UniqIndex[hashCode]; + pHash2UniqIndex[hashCode] = i; + } + p = &pCI[NextIndex]; + hashCode = hashCI(p) % hashModulus; + } + i = NextUniqIndex++; + pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; + pHash2UniqIndex[hashCode] = i; + pUniqIndex2Index[i] = NextIndex; + pIndex2UniqIndex[NextIndex] = i; + } + } + nUniqCharInfos = NextUniqIndex; + /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */ + } + } + + { + int nfontprops = pFont->info.nprops; + + int rlength = sizeof(xXF86BigfontQueryFontReply) + + nfontprops * sizeof(xFontProp) + + (nCharInfos > 0 && shmid == -1 + ? nUniqCharInfos * sizeof(xCharInfo) + + (nCharInfos + 1) / 2 * 2 * sizeof(CARD16) + : 0); + + xXF86BigfontQueryFontReply *reply = + (xXF86BigfontQueryFontReply *) ALLOCATE_LOCAL(rlength); + char *p; + + if (!reply) { + if (nCharInfos > 0) { + if (shmid == -1) + DEALLOCATE_LOCAL(pIndex2UniqIndex); + if (!pDesc) + DEALLOCATE_LOCAL(pCI); + } + return BadAlloc; + } + memset(reply, 0, rlength); + + reply->type = X_Reply; + reply->length = (rlength - sizeof(xGenericReply)) >> 2; + reply->sequenceNumber = client->sequence; + reply->minBounds = pFont->info.ink_minbounds; + reply->maxBounds = pFont->info.ink_maxbounds; + reply->minCharOrByte2 = pFont->info.firstCol; + reply->maxCharOrByte2 = pFont->info.lastCol; + reply->defaultChar = pFont->info.defaultCh; + reply->nFontProps = pFont->info.nprops; + reply->drawDirection = pFont->info.drawDirection; + reply->minByte1 = pFont->info.firstRow; + reply->maxByte1 = pFont->info.lastRow; + reply->allCharsExist = pFont->info.allExist; + reply->fontAscent = pFont->info.fontAscent; + reply->fontDescent = pFont->info.fontDescent; + reply->nCharInfos = nCharInfos; + reply->nUniqCharInfos = nUniqCharInfos; + reply->shmid = shmid; + reply->shmsegoffset = 0; + if (client->swapped) { + swaps(&reply->sequenceNumber); + swapl(&reply->length); + swapCharInfo(&reply->minBounds); + swapCharInfo(&reply->maxBounds); + swaps(&reply->minCharOrByte2); + swaps(&reply->maxCharOrByte2); + swaps(&reply->defaultChar); + swaps(&reply->nFontProps); + swaps(&reply->fontAscent); + swaps(&reply->fontDescent); + swapl(&reply->nCharInfos); + swapl(&reply->nUniqCharInfos); + swapl(&reply->shmid); + swapl(&reply->shmsegoffset); + } + p = (char *) &reply[1]; + { + FontPropPtr pFP; + + xFontProp *prFP; + + int i; + + for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p; + i < nfontprops; i++, pFP++, prFP++) { + prFP->name = pFP->name; + prFP->value = pFP->value; + if (client->swapped) { + swapl(&prFP->name); + swapl(&prFP->value); + } + } + p = (char *) prFP; + } + if (nCharInfos > 0 && shmid == -1) { + xCharInfo *pci; + + CARD16 *ps; + + int i, j; + + pci = (xCharInfo *) p; + for (i = 0; i < nUniqCharInfos; i++, pci++) { + *pci = pCI[pUniqIndex2Index[i]]; + if (client->swapped) + swapCharInfo(pci); + } + ps = (CARD16 *) pci; + for (j = 0; j < nCharInfos; j++, ps++) { + *ps = pIndex2UniqIndex[j]; + if (client->swapped) { + swaps(ps); + } + } + } + WriteToClient(client, rlength, (char *) reply); + DEALLOCATE_LOCAL(reply); + if (nCharInfos > 0) { + if (shmid == -1) + DEALLOCATE_LOCAL(pIndex2UniqIndex); + if (!pDesc) + DEALLOCATE_LOCAL(pCI); + } + return (client->noClientException); + } +} + +static int +ProcXF86BigfontDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_XF86BigfontQueryVersion: + return ProcXF86BigfontQueryVersion(client); + case X_XF86BigfontQueryFont: + return ProcXF86BigfontQueryFont(client); + default: + return BadRequest; + } +} + +static int +SProcXF86BigfontQueryVersion(ClientPtr client) +{ + REQUEST(xXF86BigfontQueryVersionReq); + swaps(&stuff->length); + return ProcXF86BigfontQueryVersion(client); +} + +static int +SProcXF86BigfontQueryFont(ClientPtr client) +{ + REQUEST(xXF86BigfontQueryFontReq); + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); + swapl(&stuff->id); + return ProcXF86BigfontQueryFont(client); +} + +static int +SProcXF86BigfontDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_XF86BigfontQueryVersion: + return SProcXF86BigfontQueryVersion(client); + case X_XF86BigfontQueryFont: + return SProcXF86BigfontQueryFont(client); + default: + return BadRequest; + } +} diff --git a/Xext/xf86bigfontsrv.h b/Xext/xf86bigfontsrv.h new file mode 100644 index 0000000..eab5287 --- /dev/null +++ b/Xext/xf86bigfontsrv.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2010 Yaakov Selkowitz + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _XF86BIGFONTSRV_H_ +#define _XF86BIGFONTSRV_H_ + +#include + +extern void XF86BigfontFreeFontShm(FontPtr); +extern void XF86BigfontCleanup(void); + +#endif diff --git a/Xext/xres.c b/Xext/xres.c new file mode 100644 index 0000000..39ba82e --- /dev/null +++ b/Xext/xres.c @@ -0,0 +1,392 @@ +/* + Copyright (c) 2002 XFree86 Inc +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "swaprep.h" +#include +#include "pixmapstr.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "extinit.h" + +static int +ProcXResQueryVersion(ClientPtr client) +{ + xXResQueryVersionReply rep; + + REQUEST_SIZE_MATCH(xXResQueryVersionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.server_major = XRES_MAJOR_VERSION; + rep.server_minor = XRES_MINOR_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.server_major); + swaps(&rep.server_minor); + } + WriteToClient(client, sizeof(xXResQueryVersionReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcXResQueryClients(ClientPtr client) +{ + /* REQUEST(xXResQueryClientsReq); */ + xXResQueryClientsReply rep; + + int *current_clients; + + int i, num_clients; + + REQUEST_SIZE_MATCH(xXResQueryClientsReq); + + current_clients = ALLOCATE_LOCAL((currentMaxClients - 1) * sizeof(int)); + + num_clients = 0; + for (i = 1; i < currentMaxClients; i++) { + if (clients[i]) { + current_clients[num_clients] = i; + num_clients++; + } + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_clients = num_clients; + rep.length = rep.num_clients * sz_xXResClient >> 2; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.num_clients); + } + WriteToClient(client, sizeof(xXResQueryClientsReply), (char *) &rep); + + if (num_clients) { + xXResClient scratch; + + for (i = 0; i < num_clients; i++) { + scratch.resource_base = clients[current_clients[i]]->clientAsMask; + scratch.resource_mask = RESOURCE_ID_MASK; + + if (client->swapped) { + + swapl(&scratch.resource_base); + swapl(&scratch.resource_mask); + } + WriteToClient(client, sz_xXResClient, (char *) &scratch); + } + } + + DEALLOCATE_LOCAL(current_clients); + + return (client->noClientException); +} + +static void +ResFindAllRes(pointer value, XID id, RESTYPE type, pointer cdata) +{ + int *counts = (int *) cdata; + + counts[(type & TypeMask) - 1]++; +} + +static int +ProcXResQueryClientResources(ClientPtr client) +{ + REQUEST(xXResQueryClientResourcesReq); + xXResQueryClientResourcesReply rep; + + int i, clientID, num_types; + + int *counts; + + REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq); + + clientID = CLIENT_ID(stuff->xid); + + /* we could remove the (clientID == 0) check if we wanted to allow + probing the X-server's resource usage */ + if (!clientID || (clientID >= currentMaxClients) || !clients[clientID]) { + client->errorValue = stuff->xid; + return BadValue; + } + + counts = ALLOCATE_LOCAL((lastResourceType + 1) * sizeof(int)); + + memset(counts, 0, (lastResourceType + 1) * sizeof(int)); + + FindAllClientResources(clients[clientID], ResFindAllRes, counts); + + num_types = 0; + + for (i = 0; i <= lastResourceType; i++) { + if (counts[i]) + num_types++; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.num_types = num_types; + rep.length = rep.num_types * sz_xXResType >> 2; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.num_types); + } + + WriteToClient(client, sizeof(xXResQueryClientResourcesReply), + (char *) &rep); + + if (num_types) { + xXResType scratch; + + for (i = 0; i < lastResourceType; i++) { + if (!counts[i]) + continue; + + if (!ResourceNames[i + 1]) { + char buf[40]; + + snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1); + RegisterResourceName(i + 1, buf); + } + + scratch.resource_type = ResourceNames[i + 1]; + scratch.count = counts[i]; + + if (client->swapped) { + + swapl(&scratch.resource_type); + swapl(&scratch.count); + } + WriteToClient(client, sz_xXResType, (char *) &scratch); + } + } + + DEALLOCATE_LOCAL(counts); + + return (client->noClientException); +} + +static unsigned long +ResGetApproxPixmapBytes(PixmapPtr pix) +{ + unsigned long nPixels; + + int bytesPerPixel; + + bytesPerPixel = pix->drawable.bitsPerPixel >> 3; + nPixels = pix->drawable.width * pix->drawable.height; + + /* Divide by refcnt as pixmap could be shared between clients, + * so total pixmap mem is shared between these. + */ + return (nPixels * bytesPerPixel) / pix->refcnt; +} + +static void +ResFindPixmaps(pointer value, XID id, pointer cdata) +{ + unsigned long *bytes = (unsigned long *) cdata; + + PixmapPtr pix = (PixmapPtr) value; + + *bytes += ResGetApproxPixmapBytes(pix); +} + +static void +ResFindWindowPixmaps(pointer value, XID id, pointer cdata) +{ + unsigned long *bytes = (unsigned long *) cdata; + + WindowPtr pWin = (WindowPtr) value; + + if (pWin->backgroundState == BackgroundPixmap) + *bytes += ResGetApproxPixmapBytes(pWin->background.pixmap); + + if (pWin->border.pixmap != NULL && !pWin->borderIsPixel) + *bytes += ResGetApproxPixmapBytes(pWin->border.pixmap); +} + +static void +ResFindGCPixmaps(pointer value, XID id, pointer cdata) +{ + unsigned long *bytes = (unsigned long *) cdata; + + GCPtr pGC = (GCPtr) value; + + if (pGC->stipple != NULL) + *bytes += ResGetApproxPixmapBytes(pGC->stipple); + + if (pGC->tile.pixmap != NULL && !pGC->tileIsPixel) + *bytes += ResGetApproxPixmapBytes(pGC->tile.pixmap); +} + +static int +ProcXResQueryClientPixmapBytes(ClientPtr client) +{ + REQUEST(xXResQueryClientPixmapBytesReq); + xXResQueryClientPixmapBytesReply rep; + + int clientID; + + unsigned long bytes; + + REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq); + + clientID = CLIENT_ID(stuff->xid); + + /* we could remove the (clientID == 0) check if we wanted to allow + probing the X-server's resource usage */ + if (!clientID || (clientID >= currentMaxClients) || !clients[clientID]) { + client->errorValue = stuff->xid; + return BadValue; + } + + bytes = 0; + + FindClientResourcesByType(clients[clientID], RT_PIXMAP, ResFindPixmaps, + (pointer) (&bytes)); + + /* + * Make sure win background pixmaps also held to account. + */ + FindClientResourcesByType(clients[clientID], RT_WINDOW, + ResFindWindowPixmaps, (pointer) (&bytes)); + + /* + * GC Tile & Stipple pixmaps too. + */ + FindClientResourcesByType(clients[clientID], RT_GC, + ResFindGCPixmaps, (pointer) (&bytes)); + + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.bytes = bytes; +#ifdef _XSERVER64 + rep.bytes_overflow = bytes >> 32; +#else + rep.bytes_overflow = 0; +#endif + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.bytes); + swapl(&rep.bytes_overflow); + } + WriteToClient(client, sizeof(xXResQueryClientPixmapBytesReply), + (char *) &rep); + + return (client->noClientException); +} + +static void +ResResetProc(ExtensionEntry * extEntry) +{ +} + +static int +ProcResDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XResQueryVersion: + return ProcXResQueryVersion(client); + case X_XResQueryClients: + return ProcXResQueryClients(client); + case X_XResQueryClientResources: + return ProcXResQueryClientResources(client); + case X_XResQueryClientPixmapBytes: + return ProcXResQueryClientPixmapBytes(client); + default: + break; + } + + return BadRequest; +} + +static int +SProcXResQueryVersion(ClientPtr client) +{ + REQUEST_SIZE_MATCH(xXResQueryVersionReq); + return ProcXResQueryVersion(client); +} + +static int +SProcXResQueryClientResources(ClientPtr client) +{ + REQUEST(xXResQueryClientResourcesReq); + + REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq); + swapl(&stuff->xid); + return ProcXResQueryClientResources(client); +} + +static int +SProcXResQueryClientPixmapBytes(ClientPtr client) +{ + REQUEST(xXResQueryClientPixmapBytesReq); + + REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq); + swapl(&stuff->xid); + return ProcXResQueryClientPixmapBytes(client); +} + +static int +SProcResDispatch(ClientPtr client) +{ + REQUEST(xReq); + + swaps(&stuff->length); + + switch (stuff->data) { + case X_XResQueryVersion: + return SProcXResQueryVersion(client); + case X_XResQueryClients: /* nothing to swap */ + return ProcXResQueryClients(client); + case X_XResQueryClientResources: + return SProcXResQueryClientResources(client); + case X_XResQueryClientPixmapBytes: + return SProcXResQueryClientPixmapBytes(client); + default: + break; + } + + return BadRequest; +} + +void +ResExtensionInit(INITARGS) +{ + (void) AddExtension(XRES_NAME, 0, 0, + ProcResDispatch, SProcResDispatch, + ResResetProc, StandardMinorOpcode); + + RegisterResourceName(RT_NONE, "NONE"); + RegisterResourceName(RT_WINDOW, "WINDOW"); + RegisterResourceName(RT_PIXMAP, "PIXMAP"); + RegisterResourceName(RT_GC, "GC"); + RegisterResourceName(RT_FONT, "FONT"); + RegisterResourceName(RT_CURSOR, "CURSOR"); + RegisterResourceName(RT_COLORMAP, "COLORMAP"); + RegisterResourceName(RT_CMAPENTRY, "COLORMAP ENTRY"); + RegisterResourceName(RT_OTHERCLIENT, "OTHER CLIENT"); + RegisterResourceName(RT_PASSIVEGRAB, "PASSIVE GRAB"); +} diff --git a/Xext/xtest.c b/Xext/xtest.c new file mode 100644 index 0000000..e0f2bdc --- /dev/null +++ b/Xext/xtest.c @@ -0,0 +1,436 @@ +/* + +Copyright 1992, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "dixevents.h" +#include "sleepuntil.h" +#define _XTEST_SERVER_ +#include + +#include "extinit.h" + +#if 0 +static unsigned char XTestReqCode; +#endif + + + +static void XTestResetProc(ExtensionEntry * /* extEntry */ + ); + +static int XTestSwapFakeInput(ClientPtr /* client */ , + xReq * /* req */ + ); + +static DISPATCH_PROC(ProcXTestCompareCursor); + +static DISPATCH_PROC(ProcXTestDispatch); + +static DISPATCH_PROC(ProcXTestFakeInput); + +static DISPATCH_PROC(ProcXTestGetVersion); + +static DISPATCH_PROC(ProcXTestGrabControl); + +static DISPATCH_PROC(SProcXTestCompareCursor); + +static DISPATCH_PROC(SProcXTestDispatch); + +static DISPATCH_PROC(SProcXTestFakeInput); + +static DISPATCH_PROC(SProcXTestGetVersion); + +static DISPATCH_PROC(SProcXTestGrabControl); + +void +XTestExtensionInit(INITARGS) +{ +#if 0 + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(XTestExtensionName, 0, 0, + ProcXTestDispatch, SProcXTestDispatch, + XTestResetProc, StandardMinorOpcode)) != 0) + XTestReqCode = (unsigned char) extEntry->base; +#else + (void) AddExtension(XTestExtensionName, 0, 0, + ProcXTestDispatch, SProcXTestDispatch, + XTestResetProc, StandardMinorOpcode); +#endif +} + + /*ARGSUSED*/ static void +XTestResetProc(extEntry) +ExtensionEntry *extEntry; +{ +} + +static int +ProcXTestGetVersion(client) +ClientPtr client; +{ + xXTestGetVersionReply rep; + + + REQUEST_SIZE_MATCH(xXTestGetVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = XTestMajorVersion; + rep.minorVersion = XTestMinorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swaps(&rep.minorVersion); + } + WriteToClient(client, sizeof(xXTestGetVersionReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcXTestCompareCursor(client) +ClientPtr client; +{ + REQUEST(xXTestCompareCursorReq); + xXTestCompareCursorReply rep; + + WindowPtr pWin; + + CursorPtr pCursor; + + + REQUEST_SIZE_MATCH(xXTestCompareCursorReq); + pWin = (WindowPtr) LookupWindow(stuff->window, client); + if (!pWin) + return (BadWindow); + if (stuff->cursor == None) + pCursor = NullCursor; + else if (stuff->cursor == XTestCurrentCursor) + pCursor = GetSpriteCursor(); + else { + pCursor = (CursorPtr) LookupIDByType(stuff->cursor, RT_CURSOR); + if (!pCursor) { + client->errorValue = stuff->cursor; + return (BadCursor); + } + } + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.same = (wCursor(pWin) == pCursor); + if (client->swapped) { + swaps(&rep.sequenceNumber); + } + WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcXTestFakeInput(client) +ClientPtr client; +{ + REQUEST(xXTestFakeInputReq); + int nev; + + xEvent *ev; + + DeviceIntPtr dev = NULL; + + WindowPtr root; + + int type; + + + nev = (stuff->length << 2) - sizeof(xReq); + if ((nev % sizeof(xEvent)) || !nev) + return BadLength; + nev /= sizeof(xEvent); + UpdateCurrentTime(); + ev = (xEvent *) &((xReq *) stuff)[1]; + type = ev->u.u.type & 0177; + { + if (nev != 1) + return BadLength; + switch (type) { + case KeyPress: + case KeyRelease: + case MotionNotify: + case ButtonPress: + case ButtonRelease: + break; + default: + client->errorValue = ev->u.u.type; + return BadValue; + } + } + if (ev->u.keyButtonPointer.time) { + TimeStamp activateTime; + + CARD32 ms; + + activateTime = currentTime; + ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; + if (ms < activateTime.milliseconds) + activateTime.months++; + activateTime.milliseconds = ms; + ev->u.keyButtonPointer.time = 0; + + /* see mbuf.c:QueueDisplayRequest for code similar to this */ + + if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) { + return BadAlloc; + } + /* swap the request back so we can simply re-execute it */ + if (client->swapped) { + (void) XTestSwapFakeInput(client, (xReq *) stuff); + swaps(&stuff->length); + } + ResetCurrentRequest(client); + client->sequence--; + return Success; + } + switch (type) { + case KeyPress: + case KeyRelease: + dev = (DeviceIntPtr) LookupKeyboardDevice(); + if (ev->u.u.detail < dev->key->curKeySyms.minKeyCode || + ev->u.u.detail > dev->key->curKeySyms.maxKeyCode) { + client->errorValue = ev->u.u.detail; + return BadValue; + } + break; + case MotionNotify: + dev = (DeviceIntPtr) LookupPointerDevice(); + if (ev->u.keyButtonPointer.root == None) + root = GetCurrentRootWindow(); + else { + root = LookupWindow(ev->u.keyButtonPointer.root, client); + if (!root) + return BadWindow; + if (root->parent) { + client->errorValue = ev->u.keyButtonPointer.root; + return BadValue; + } + } + if (ev->u.u.detail == xTrue) { + int x, y; + + GetSpritePosition(&x, &y); + ev->u.keyButtonPointer.rootX += x; + ev->u.keyButtonPointer.rootY += y; + } + else if (ev->u.u.detail != xFalse) { + client->errorValue = ev->u.u.detail; + return BadValue; + } + + + if (ev->u.keyButtonPointer.rootX < 0) + ev->u.keyButtonPointer.rootX = 0; + else if (ev->u.keyButtonPointer.rootX >= root->drawable.width) + ev->u.keyButtonPointer.rootX = root->drawable.width - 1; + if (ev->u.keyButtonPointer.rootY < 0) + ev->u.keyButtonPointer.rootY = 0; + else if (ev->u.keyButtonPointer.rootY >= root->drawable.height) + ev->u.keyButtonPointer.rootY = root->drawable.height - 1; + + if (root != GetCurrentRootWindow()) + { + NewCurrentScreen(root->drawable.pScreen, + ev->u.keyButtonPointer.rootX, + ev->u.keyButtonPointer.rootY); + return client->noClientException; + } + (*root->drawable.pScreen->SetCursorPosition) + (root->drawable.pScreen, + ev->u.keyButtonPointer.rootX, ev->u.keyButtonPointer.rootY, FALSE); + break; + case ButtonPress: + case ButtonRelease: + dev = (DeviceIntPtr) LookupPointerDevice(); + if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) { + client->errorValue = ev->u.u.detail; + return BadValue; + } + break; + } + if (screenIsSaved == SCREEN_SAVER_ON) + SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset); + ev->u.keyButtonPointer.time = currentTime.milliseconds; + (*dev->public.processInputProc) (ev, dev, nev); + return client->noClientException; +} + +static int +ProcXTestGrabControl(client) +ClientPtr client; +{ + REQUEST(xXTestGrabControlReq); + + REQUEST_SIZE_MATCH(xXTestGrabControlReq); + if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) { + client->errorValue = stuff->impervious; + return (BadValue); + } + if (stuff->impervious) + MakeClientGrabImpervious(client); + else + MakeClientGrabPervious(client); + return (client->noClientException); +} + +static int +ProcXTestDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XTestGetVersion: + return ProcXTestGetVersion(client); + case X_XTestCompareCursor: + return ProcXTestCompareCursor(client); + case X_XTestFakeInput: + return ProcXTestFakeInput(client); + case X_XTestGrabControl: + return ProcXTestGrabControl(client); + default: + return BadRequest; + } +} + +static int +SProcXTestGetVersion(client) +ClientPtr client; +{ + + REQUEST(xXTestGetVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xXTestGetVersionReq); + swaps(&stuff->minorVersion); + return ProcXTestGetVersion(client); +} + +static int +SProcXTestCompareCursor(client) +ClientPtr client; +{ + + REQUEST(xXTestCompareCursorReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xXTestCompareCursorReq); + swapl(&stuff->window); + swapl(&stuff->cursor); + return ProcXTestCompareCursor(client); +} + +static int +XTestSwapFakeInput(client, req) +ClientPtr client; + +xReq *req; +{ + int nev; + + xEvent *ev; + + xEvent sev; + + EventSwapPtr proc; + + nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); + for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { + /* Swap event */ + proc = EventSwapVector[ev->u.u.type & 0177]; + /* no swapping proc; invalid event type? */ + if (!proc || proc == NotImplemented) { + client->errorValue = ev->u.u.type; + return BadValue; + } + (*proc) (ev, &sev); + *ev = sev; + } + return Success; +} + +static int +SProcXTestFakeInput(client) +ClientPtr client; +{ + + REQUEST(xReq); + + swaps(&stuff->length); + int n = XTestSwapFakeInput(client, stuff); + if (n != Success) + return n; + return ProcXTestFakeInput(client); +} + +static int +SProcXTestGrabControl(client) +ClientPtr client; +{ + + REQUEST(xXTestGrabControlReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xXTestGrabControlReq); + return ProcXTestGrabControl(client); +} + +static int +SProcXTestDispatch(client) +ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) { + case X_XTestGetVersion: + return SProcXTestGetVersion(client); + case X_XTestCompareCursor: + return SProcXTestCompareCursor(client); + case X_XTestFakeInput: + return SProcXTestFakeInput(client); + case X_XTestGrabControl: + return SProcXTestGrabControl(client); + default: + return BadRequest; + } +} diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..a4fa9a2 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,10 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..3ea5d6b --- /dev/null +++ b/configure.ac @@ -0,0 +1,687 @@ +dnl Copyright © 2003-2005 Keith Packard, Daniel Stone +dnl Copyright © 2013 Lauri Kasanen +dnl +dnl Permission to use, copy, modify, distribute, and sell this software and its +dnl documentation for any purpose is hereby granted without fee, provided that +dnl the above copyright notice appear in all copies and that both that +dnl copyright notice and this permission notice appear in supporting +dnl documentation, and that the names of Keith Packard and Daniel Stone not be +dnl used in advertising or publicity pertaining to distribution of the software +dnl without specific, written prior permission. Keith Packard and Daniel Stone +dnl make no representations about the suitability of this software for any +dnl purpose. It is provided "as is" without express or implied warranty. +dnl +dnl KEITH PACKARD AND DANIEL STONE DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +dnl SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +dnl IN NO EVENT SHALL KEITH PACKARD OR DANIEL STONE BE LIABLE FOR ANY SPECIAL, +dnl INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +dnl LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +dnl OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +dnl PERFORMANCE OF THIS SOFTWARE. +dnl +dnl Process this file with autoconf to create configure. + +AC_PREREQ(2.57) +AC_INIT([tinyx], 1.0) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign -Wall]) + +dnl this gets generated by autoheader, and thus contains all the defines. we +dnl don't ever actually use it, internally. +AC_CONFIG_HEADERS(include/do-not-use-config.h) +dnl dix-config.h covers most of the DIX (i.e. everything but the DDX, not just +dnl dix/). +AC_CONFIG_HEADERS(include/dix-config.h) +dnl kdrive-config.h covers the kdrive DDX +AC_CONFIG_HEADERS(include/kdrive-config.h) + +AC_PROG_CC +AM_PROG_AS +AC_PROG_INSTALL +AC_PROG_LN_S +AC_DISABLE_SHARED +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG +AC_PROG_LEX +AC_PROG_YACC +XORG_PROG_RAWCPP + +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_BIGENDIAN([ENDIAN="X_BIG_ENDIAN"], [ENDIAN="X_LITTLE_ENDIAN"]) + +AC_CHECK_SIZEOF([unsigned long]) +if test "$ac_cv_sizeof_unsigned_long" = 8; then + AC_DEFINE(_XSERVER64, 1, [Define to 1 if unsigned long is 64 bits.]) +fi + +AC_TYPE_PID_T + +dnl Checks for library functions. +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([geteuid getuid link memmove memset mkstemp strchr strrchr \ + strtol getopt getopt_long vsnprintf]) +AC_FUNC_ALLOCA +dnl Old HAS_* names used in os/*.c. +AC_CHECK_FUNC([getdtablesize], + AC_DEFINE(HAS_GETDTABLESIZE, 1, [Have the `getdtablesize' function.])) +AC_CHECK_FUNC([getifaddrs], + AC_DEFINE(HAS_GETIFADDRS, 1, [Have the `getifaddrs' function.])) +AC_CHECK_FUNC([getpeereid], + AC_DEFINE(HAS_GETPEEREID, 1, [Have the `getpeereid' function.])) +AC_CHECK_FUNC([getpeerucred], + AC_DEFINE(HAS_GETPEERUCRED, 1, [Have the `getpeerucred' function.])) +AC_CHECK_FUNC([strlcat], HAVE_STRLCAT=yes, HAVE_STRLCAT=no) +AM_CONDITIONAL(NEED_STRLCAT, [test x$HAVE_STRLCAT = xno]) + +AM_CONDITIONAL(NEED_VSNPRINTF, [test x$HAVE_VSNPRINTF = xno]) + +dnl Check for mmap support for Xvfb +AC_CHECK_FUNC([mmap], AC_DEFINE(HAS_MMAP, 1, [Have the `mmap' function.])) + +dnl Find the math libary +AC_CHECK_LIB(m, sqrt) + +dnl APM header +AC_CHECK_HEADERS([linux/apm_bios.h], LNXAPM=yes) +AM_CONDITIONAL(LNXAPM, [test "x$LNXAPM" = xyes]) + +dnl fbdev header +AC_CHECK_HEADERS([linux/fb.h], FBDEV=yes) +AM_CONDITIONAL(FBDEVHW, [test "x$FBDEV" = xyes]) + +dnl MTRR header +AC_CHECK_HEADERS([asm/mtrr.h], ac_cv_asm_mtrr_h=yes) +if test "x$ac_cv_asm_mtrr_h" = xyes; then + HAVE_MTRR=yes +fi + +dnl BSD MTRR header +AC_CHECK_HEADERS([sys/memrange.h], ac_cv_memrange_h=yes) +if test "x$ac_cv_memrange_h" = xyes; then + HAVE_MTRR=yes +fi + +if test "x$HAVE_MTRR" = xyes; then + AC_DEFINE(HAS_MTRR_SUPPORT, 1, [MTRR support available]) +fi + +dnl A NetBSD MTRR header +AC_CHECK_HEADERS([machine/mtrr.h], ac_cv_machine_mtrr_h=yes) +if test "x$ac_cv_machine_mtrr_h" = xyes; then + AC_DEFINE(HAS_MTRR_BUILTIN, 1, [Define to 1 if NetBSD built-in MTRR + support is available]) +fi + +dnl FreeBSD kldload support (sys/linker.h) +AC_CHECK_HEADERS([sys/linker.h], + [ac_cv_sys_linker_h=yes], + [ac_cv_sys_linker_h=no], + [#include ]) +AM_CONDITIONAL(FREEBSD_KLDLOAD, [test "x$ac_cv_sys_linker_h" = xyes]) + +AC_CACHE_CHECK([for SYSV IPC], + ac_cv_sysv_ipc, + [AC_TRY_LINK([ +#include +],[ +{ + int id; + id = shmget(IPC_PRIVATE, 512, SHM_W | SHM_R); + if (id < 0) return -1; + return shmctl(id, IPC_RMID, 0); +}], + [ac_cv_sysv_ipc=yes], + [ac_cv_sysv_ipc=no])]) +if test "x$ac_cv_sysv_ipc" = xyes; then + AC_DEFINE(HAVE_SYSV_IPC, 1, [Define to 1 if SYSV IPC is available]) +fi + +dnl --------------------------------------------------------------------------- +dnl Bus options and CPU capabilities. Replaces logic in +dnl hw/xfree86/os-support/bus/Makefile.am, among others. +dnl --------------------------------------------------------------------------- +DEFAULT_INT10="x86emu" + +dnl Override defaults as needed for specific platforms: + +case $host_cpu in + alpha*) + ALPHA_VIDEO=yes + case $host_os in + *netbsd*) AC_DEFINE(USE_ALPHA_PIO, 1, [NetBSD PIO alpha IO]) ;; + esac + ;; + arm*) + ARM_VIDEO=yes + ;; + i*86) + I386_VIDEO=yes + case $host_os in + *linux*) DEFAULT_INT10=vm86 ;; + *freebsd*) AC_DEFINE(USE_DEV_IO) ;; + *netbsd*) AC_DEFINE(USE_I386_IOPL) + SYS_LIBS=-li386 + ;; + *openbsd*) AC_DEFINE(USE_I386_IOPL) + SYS_LIBS=-li386 + ;; + esac + ;; + powerpc*) + PPC_VIDEO=yes + case $host_os in + *freebsd*) DEFAULT_INT10=stub ;; + esac + ;; + sparc*) + xorg_loader_sparcmuldiv="yes" + SPARC64_VIDEO=yes + BSD_ARCH_SOURCES="sparc64_video.c ioperm_noop.c" + ;; + x86_64*|amd64*) + I386_VIDEO=yes + case $host_os in + *freebsd*) AC_DEFINE(USE_DEV_IO, 1, [BSD /dev/io]) ;; + *netbsd*) AC_DEFINE(USE_I386_IOPL, 1, [BSD i386 iopl]) + SYS_LIBS=-lx86_64 + ;; + *openbsd*) AC_DEFINE(USE_AMD64_IOPL, 1, [BSD AMD64 iopl]) + SYS_LIBS=-lamd64 + ;; + esac + ;; +esac + +dnl BSD *_video.c selection +AM_CONDITIONAL(ALPHA_VIDEO, [test "x$ALPHA_VIDEO" = xyes]) +AM_CONDITIONAL(ARM_VIDEO, [test "x$ARM_VIDEO" = xyes]) +AM_CONDITIONAL(I386_VIDEO, [test "x$I386_VIDEO" = xyes]) +AM_CONDITIONAL(PPC_VIDEO, [test "x$PPC_VIDEO" = xyes]) +AM_CONDITIONAL(SPARC64_VIDEO, [test "x$SPARC64_VIDEO" = xyes]) + +DRI=no +dnl it would be nice to autodetect these *CONS_SUPPORTs +case $host_os in + *freebsd*) + case $host_os in + kfreebsd*-gnu) ;; + *) AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) ;; + esac + AC_DEFINE(PCCONS_SUPPORT, 1, [System has PC console]) + AC_DEFINE(PCVT_SUPPORT, 1, [System has PCVT console]) + AC_DEFINE(SYSCONS_SUPPORT, 1, [System has syscons console]) + ;; + *netbsd*) + AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) + AC_DEFINE(PCCONS_SUPPORT, 1, [System has PC console]) + AC_DEFINE(WSCONS_SUPPORT, 1, [System has wscons console]) + ;; + *openbsd*) + AC_DEFINE(CSRG_BASED, 1, [System is BSD-like]) + AC_DEFINE(PCVT_SUPPORT, 1, [System has PC console]) + AC_DEFINE(WSCONS_SUPPORT, 1, [System has wscons console]) + ;; +esac + +OSNAME=`uname -srm` +AC_DEFINE_UNQUOTED(OSNAME, "$OSNAME", + [Define to OS Name string to display for build OS in Xorg log]) + +DEFAULT_VENDOR_NAME="TinyCore Linux" +DEFAULT_VENDOR_NAME_SHORT="TinyCore" +VERSION_MAJOR=1 +VERSION_MINOR=0 +VERSION_PATCH=0 +VERSION_SNAP=0 +RELEASE_DATE="9 Nov 2013" +DEFAULT_VENDOR_WEB="http://tinycorelinux.com" + +m4_ifdef([AS_HELP_STRING], , [m4_define([AS_HELP_STRING], m4_defn([AC_HELP_STRING]))]) + +dnl Build options. +AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror], + [Treat warnings as errors (default: disabled)]), + [WERROR=$enableval], [WERROR=no]) +AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], + [Enable debugging (default: disabled)]), + [DEBUGGING=$enableval], [DEBUGGING=no]) +AC_ARG_WITH(int10, AS_HELP_STRING([--with-int10=BACKEND], [int10 backend: vm86, x86emu or stub]), + [INT10="$withval"], + [INT10="$DEFAULT_INT10"]) +AC_ARG_WITH(vendor-name, AS_HELP_STRING([--with-vendor-string=VENDOR], + [Vendor string reported by the server]), + [ VENDOR_STRING="$withval" ], + [ VENDOR_STRING="$DEFAULT_VENDOR_NAME" ]) +AC_ARG_WITH(vendor-name-short, AS_HELP_STRING([--with-vendor-string-short=VENDOR], + [Short version of vendor string reported by the server]), + [ VENDOR_STRING_SHORT="$withval" ], + [ VENDOR_STRING_SHORT="$DEFAULT_VENDOR_NAME_SHORT" ]) +AC_ARG_WITH(vendor-web, AS_HELP_STRING([--with-vendor-web=URL], + [Vendor web address reported by the server]), + [ VENDOR_WEB="$withval" ], + [ VENDOR_WEB="$DEFAULT_VENDOR_WEB" ]) +AC_ARG_WITH(builder-addr, AS_HELP_STRING([--with-builder-addr=ADDRESS], + [Builder address (default: xorg@lists.freedesktop.org)]), + [ BUILDERADDR="$withval" ], + [ BUILDERADDR="xorg@lists.freedesktop.org" ]) +AC_ARG_WITH(fontdir, AS_HELP_STRING([--with-fontdir=FONTDIR], [Path to top level dir where fonts are installed (default: ${libdir}/X11/fonts)]), + [ FONTDIR="$withval" ], + [ FONTDIR="${libdir}/X11/fonts" ]) +DEFAULT_FONT_PATH="${FONTDIR}/misc/,${FONTDIR}/TTF/,${FONTDIR}/OTF,${FONTDIR}/Type1/,${FONTDIR}/100dpi/,${FONTDIR}/75dpi/" +AC_ARG_WITH(default-font-path, AS_HELP_STRING([--with-default-font-path=PATH], [Comma separated list of font dirs]), + [ FONTPATH="$withval" ], + [ FONTPATH="${DEFAULT_FONT_PATH}" ]) + +dnl Extensions. +AC_ARG_ENABLE(xres, AS_HELP_STRING([--disable-xres], [Build XRes extension (default: enabled)]), [RES=$enableval], [RES=yes]) +AC_ARG_ENABLE(screensaver, AS_HELP_STRING([--disable-screensaver], [Build ScreenSaver extension (default: enabled)]), [SCREENSAVER=$enableval], [SCREENSAVER=yes]) +AC_ARG_ENABLE(xdmcp, AS_HELP_STRING([--disable-xdmcp], [Build XDMCP extension (default: auto)]), [XDMCP=$enableval], [XDMCP=auto]) +AC_ARG_ENABLE(xdm-auth-1, AS_HELP_STRING([--disable-xdm-auth-1], [Build XDM-Auth-1 extension (default: auto)]), [XDMAUTH=$enableval], [XDMAUTH=auto]) +AC_ARG_ENABLE(dbe, AS_HELP_STRING([--disable-dbe], [Build DBE extension (default: enabled)]), [DBE=$enableval], [DBE=yes]) +AC_ARG_ENABLE(xf86bigfont, AS_HELP_STRING([--disable-xf86bigfont], [Build XF86 Big Font extension (default: enabled)]), [XF86BIGFONT=$enableval], [XF86BIGFONT=yes]) +AC_ARG_ENABLE(dpms, AS_HELP_STRING([--disable-dpms], [Build DPMS extension (default: enabled)]), [DPMSExtension=$enableval], [DPMSExtension=yes]) + +dnl kdrive and its subsystems +AC_ARG_ENABLE(kdrive, AS_HELP_STRING([--enable-kdrive], [Build kdrive servers (default: yes)]), [KDRIVE=$enableval], [KDRIVE=yes]) + + +dnl chown/chmod to be setuid root as part of build +dnl Replaces InstallXserverSetUID in imake +AC_ARG_ENABLE(install-setuid, + AS_HELP_STRING([--enable-install-setuid], + [Install Xorg server as owned by root with setuid bit (default: auto)]), + [SETUID=$enableval], [SETUID=auto]) +AC_MSG_CHECKING([to see if we can install the Xorg server as root]) +if test "x$SETUID" = "xauto" ; then + case $host_os in + darwin*) SETUID="no" ;; + *) + case $host_cpu in + sparc) SETUID="no" ;; + *) SETUID="yes" ;; + esac + esac + if test "x$SETUID" = xyes; then + touch testfile + chown root testfile > /dev/null 2>&1 || SETUID="no" + rm -f testfile + fi +fi +AC_MSG_RESULT([$SETUID]) +AM_CONDITIONAL(INSTALL_SETUID, [test "x$SETUID" = "xyes"]) + +dnl Issue an error if xtrans.m4 was not found and XTRANS_CONNECTION_FLAGS macro +dnl was not expanded, since xorg-server with no transport types is rather useless. +dnl +dnl If you're seeing an error here, be sure you installed the lib/xtrans module +dnl first and if it's not in the default location, that you set the ACLOCAL +dnl environment variable to find it, such as: +dnl ACLOCAL="aclocal -I ${PREFIX}/share/aclocal" +m4_pattern_forbid([^XTRANS_CONNECTION_FLAGS$]) + +# Transport selection macro from xtrans.m4 +XTRANS_CONNECTION_FLAGS + +# Secure RPC detection macro from xtrans.m4 +XTRANS_SECURE_RPC_FLAGS + +AM_CONDITIONAL(INT10_VM86, [test "x$INT10" = xvm86]) +AM_CONDITIONAL(INT10_X86EMU, [test "x$INT10" = xx86emu]) +AM_CONDITIONAL(INT10_STUB, [test "x$INT10" = xstub]) +if test "x$INT10" = xyes; then + dnl VM86 headers + AC_CHECK_HEADERS([sys/vm86.h sys/io.h]) +fi + +dnl --------------------------------------------------------------------------- +dnl Extension section +dnl --------------------------------------------------------------------------- +XEXT_INC='-I$(top_srcdir)/Xext' +XEXT_LIB='$(top_builddir)/Xext/libXext.la' +XEXTXORG_LIB='$(top_builddir)/Xext/libXextbuiltin.la' + +dnl Core modules for most extensions, et al. +REQUIRED_MODULES="[randrproto >= 1.2] renderproto [fixesproto >= 4.0] [damageproto >= 1.1] xcmiscproto xextproto xproto xtrans xf86bigfontproto [scrnsaverproto >= 1.1] bigreqsproto resourceproto fontsproto inputproto [kbproto >= 1.0.3]" +REQUIRED_LIBS="xfont fontenc" + +AM_CONDITIONAL(SCREENSAVER, [test "x$SCREENSAVER" = xyes]) +if test "x$SCREENSAVER" = xyes; then + AC_DEFINE(SCREENSAVER, 1, [Support MIT-SCREEN-SAVER extension]) +fi + +AM_CONDITIONAL(RES, [test "x$RES" = xyes]) +if test "x$RES" = xyes; then + AC_DEFINE(RES, 1, [Support X resource extension]) + REQUIRED_MODULES="$REQUIRED_MODULES resourceproto" +fi + +AM_CONDITIONAL(DBE, [test "x$DBE" = xyes]) +if test "x$DBE" = xyes; then + AC_DEFINE(DBE, 1, [Support DBE extension]) + DBE_LIB='$(top_builddir)/dbe/libdbe.la' +fi + +AM_CONDITIONAL(XF86BIGFONT, [test "x$XF86BIGFONT" = xyes]) +if test "x$XF86BIGFONT" = xyes; then + AC_DEFINE(XF86BIGFONT, 1, [Support XF86 Big font extension]) +fi + +AM_CONDITIONAL(DPMSExtension, [test "x$DPMSExtension" = xyes]) +if test "x$DPMSExtension" = xyes; then + AC_DEFINE(DPMSExtension, 1, [Support DPMS extension]) +fi + +RENDER_LIB='$(top_builddir)/render/librender.la' +RENDER_INC='-I$(top_srcdir)/render' + +RANDR_LIB='$(top_builddir)/randr/librandr.la' +RANDR_INC='-I$(top_srcdir)/randr' + +FIXES_LIB='$(top_builddir)/xfixes/libxfixes.la' +FIXES_INC='-I$(top_srcdir)/xfixes' + +DAMAGE_LIB='$(top_builddir)/damageext/libdamageext.la' +DAMAGE_INC='-I$(top_srcdir)/damageext' +MIEXT_DAMAGE_LIB='$(top_builddir)/miext/damage/libdamage.la' +MIEXT_DAMAGE_INC='-I$(top_srcdir)/miext/damage' + +AC_CHECK_FUNC(strcasecmp, [], AC_DEFINE([NEED_STRCASECMP], 1, + [Do not have `strcasecmp'.])) + +PKG_CHECK_MODULES([XDMCP], [xdmcp], [have_libxdmcp="yes"], [have_libxdmcp="no"]) +if test "x$have_libxdmcp" = xyes; then + AC_CHECK_LIB(Xdmcp, XdmcpWrap, [have_xdmcpwrap="yes"], [have_xdmcpwrap="no"], [$XDMCP_LIBS]) +fi +if test "x$XDMCP" = xauto; then + if test "x$have_libxdmcp" = xyes; then + XDMCP=yes + else + XDMCP=no + fi +fi +if test "x$XDMAUTH" = xauto; then + if test "x$have_libxdmcp" = xyes && test "x$have_xdmcpwrap" = xyes; then + XDMAUTH=yes + else + XDMAUTH=no + fi +fi + +AM_CONDITIONAL(XDMCP, [test "x$XDMCP" = xyes]) +if test "x$XDMCP" = xyes; then + AC_DEFINE(XDMCP, 1, [Support XDM Control Protocol]) + REQUIRED_LIBS="$REQUIRED_LIBS xdmcp" + XDMCP_MODULES="xdmcp" +fi + +AM_CONDITIONAL(XDMAUTH, [test "x$XDMAUTH" = xyes]) +if test "x$XDMAUTH" = xyes; then + AC_DEFINE(HASXDMAUTH,1,[Support XDM-AUTH*-1]) + if ! test "x$XDMCP" = xyes; then + REQUIRED_LIBS="$REQUIRED_LIBS xdmcp" + XDMCP_MODULES="xdmcp" + fi +fi + +VENDOR_RELEASE="((($VERSION_MAJOR) * 10000000) + (($VERSION_MINOR) * 100000) + (($VERSION_PATCH) * 1000) + $VERSION_SNAP)" + +if test $VERSION_SNAP = "0"; then + if test $VERSION_PATCH = "0"; then + VENDOR_VERSION_STRING="${VERSION_MAJOR}.${VERSION_MINOR}" + else + VENDOR_VERSION_STRING="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + fi +else + VENDOR_VERSION_STRING="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_SNAP}" +fi + +VENDOR_RELEASE_STRING="Release ${VENDOR_VERSION_STRING}" +VENDOR_MAN_VERSION="Version ${VENDOR_VERSION_STRING}" + +AC_DEFINE_DIR(COMPILEDDEFAULTFONTPATH, FONTPATH, [Default font path]) +AC_DEFINE_DIR(BASE_FONT_PATH, FONTDIR, [Default base font path]) +AC_DEFINE_UNQUOTED(XVENDORNAME, ["$VENDOR_STRING"], [Vendor name]) +AC_DEFINE_UNQUOTED(XVENDORNAMESHORT, ["$VENDOR_STRING_SHORT"], [Short vendor name]) +AC_DEFINE_UNQUOTED(XORG_RELEASE, ["$VENDOR_RELEASE_STRING"], [Vendor release]) +AC_DEFINE_UNQUOTED(XORG_DATE, ["$RELEASE_DATE"], [Vendor release]) +AC_DEFINE_UNQUOTED(XORG_MAN_VERSION, ["$VENDOR_MAN_VERSION"], [Vendor man version]) +AC_DEFINE_UNQUOTED(BUILDERADDR, ["$BUILDERADDR"], [Builder address]) +AC_DEFINE_UNQUOTED(OSNAME, ["$OSNAME"], [Operating System Name]) +AC_SUBST([VENDOR_STRING]) +AC_SUBST([VENDOR_STRING_SHORT]) +AC_SUBST([VENDOR_RELEASE]) +AC_SUBST([VENDOR_MAN_VERSION]) + +AC_DEFINE(SMART_SCHEDULE, 1, [Include time-based scheduler]) +AM_CONDITIONAL(DEBUG, test "x$DEBUGGING" = xyes) + +if ! test "x$DEBUGGING" = xyes; then + AC_DEFINE(NDEBUG, 1, [Disable some debugging code]) +fi + +DIX_LIB='$(top_builddir)/dix/libdix.la' +OS_LIB='$(top_builddir)/os/libos.la' +MI_LIB='$(top_builddir)/mi/libmi.la' +MI_EXT_LIB='$(top_builddir)/mi/libmiext.la' +MI_INC='-I$(top_srcdir)/mi' +FB_LIB='$(top_builddir)/fb/libfb.la' +FB_INC='-I$(top_srcdir)/fb' +MIEXT_SHADOW_INC='-I$(top_srcdir)/miext/shadow' +MIEXT_SHADOW_LIB='$(top_builddir)/miext/shadow/libshadow.la' +CORE_INCS='-I$(top_srcdir)/include -I$(top_builddir)/include' + +PKG_CHECK_MODULES([XSERVERCFLAGS], [$REQUIRED_MODULES $REQUIRED_LIBS]) +PKG_CHECK_MODULES([XSERVERLIBS], [$REQUIRED_LIBS]) + +XSERVER_CFLAGS="${XSERVERCFLAGS_CFLAGS}" +XSERVER_LIBS="${XSERVERLIBS_LIBS} ${SYS_LIBS} -lm" +AC_SUBST([SYS_LIBS]) + +AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], + [AC_CHECK_LIB([rt], [clock_gettime], [have_clock_gettime=-lrt], + [have_clock_gettime=no])]) + +AC_MSG_CHECKING([for a useful monotonic clock ...]) + +if ! test "x$have_clock_gettime" = xno; then + if ! test "x$have_clock_gettime" = xyes; then + LIBS="$have_clock_gettime" + else + LIBS="" + fi + + AC_RUN_IFELSE([AC_LANG_SOURCE([ +#define _POSIX_C_SOURCE 199309L +#include + +int main(int argc, char *argv[]) { + struct timespec tp; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + return 0; + else + return 1; +} + ])], [MONOTONIC_CLOCK=yes], [MONOTONIC_CLOCK=no], + [MONOTONIC_CLOCK="cross compiling"]) +else + MONOTONIC_CLOCK=no +fi + +AC_MSG_RESULT([$MONOTONIC_CLOCK]) + +if test "x$MONOTONIC_CLOCK" = xyes; then + AC_DEFINE(MONOTONIC_CLOCK, 1, [Have monotonic clock from clock_gettime()]) + XSERVER_LIBS="$XSERVER_LIBS $LIBS" +fi + +XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $DAMAGE_INC $FIXES_INC $MI_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC" +AC_DEFINE_UNQUOTED(X_BYTE_ORDER,[$ENDIAN],[Endian order]) + +AC_SUBST([XSERVER_LIBS]) + +dnl --------------------------------------------------------------------------- +dnl DDX section. +dnl --------------------------------------------------------------------------- + +# XORG_CORE_LIBS is needed even if you're not building the Xorg DDX +XORG_CORE_LIBS="$DIX_LIB" +AC_SUBST([XORG_CORE_LIBS]) + +xorg_bus_linuxpci=no +xorg_bus_freebsdpci=no +xorg_bus_netbsdpci=no +xorg_bus_ix86pci=no +xorg_bus_ppcpci=no +xorg_bus_sparcpci=no +xorg_bus_sparc=no + +AM_CONDITIONAL([XORG], [test "x$XORG" = xyes]) +AM_CONDITIONAL([XORG_BUS_LINUXPCI], [test "x$xorg_bus_linuxpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_FREEBSDPCI], [test "x$xorg_bus_freebsdpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_NETBSDPCI], [test "x$xorg_bus_netbsdpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_IX86PCI], [test "x$xorg_bus_ix86pci" = xyes]) +AM_CONDITIONAL([XORG_BUS_PPCPCI], [test "x$xorg_bus_ppcpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_SPARCPCI], [test "x$xorg_bus_sparcpci" = xyes]) +AM_CONDITIONAL([XORG_BUS_SPARC], [test "x$xorg_bus_sparc" = xyes]) +AM_CONDITIONAL([XORG_LOADER_SPARC], [test "x$xorg_loader_sparcmuldiv" = xyes]) +AM_CONDITIONAL([LINUX_IA64], [test "x$linux_ia64" = xyes]) +AM_CONDITIONAL([LINUX_ALPHA], [test "x$linux_alpha" = xyes]) +AM_CONDITIONAL([LNXACPI], [test "x$linux_acpi" = xyes]) + +dnl kdrive DDX + +AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes]) +if test "$KDRIVE" = yes; then + AC_DEFINE(KDRIVESERVER,1,[Build Kdrive X server]) + AC_DEFINE(KDRIVEDDXACTIONS,,[Build kdrive ddx]) + + AC_CHECK_HEADERS([asm/vm86.h sys/io.h]) + if test "$ac_cv_header_asm_vm86_h" = yes; then + AC_DEFINE(KDRIVEVESA, 1, [Build VESA-based kdrive servers]) + fi + + AC_CHECK_HEADERS([linux/fb.h]) + if test "$ac_cv_header_linux_fb_h" = yes; then + AC_DEFINE(KDRIVEFBDEV, 1, [Build fbdev-based kdrive server]) + fi + + # damage shadow extension fb mi + KDRIVE_INC='-I$(top_srcdir)/kdrive/src' + KDRIVE_PURE_INCS="$KDRIVE_INC $MIEXT_DAMAGE_INC $MIEXT_SHADOW_INC $XEXT_INC $FB_INC $MI_INC" + KDRIVE_OS_INC='-I$(top_srcdir)/kdrive/linux' + KDRIVE_INCS="$KDRIVE_PURE_INCS $KDRIVE_OS_INC" + + KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H" + + # dix os fb mi extension glx (NOTYET) damage shadow + #KDRIVE_PURE_LIBS="$DIX_LIB $OS_LIB $FB_LIB $XEXT_LIB $MIEXT_DAMAGE_LIB \ + # $MIEXT_SHADOW_LIB" + KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RENDER_LIB $RANDR_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $OS_LIB" + KDRIVE_LIB='$(top_builddir)/kdrive/src/libkdrive.a' + case $host_os in + *linux*) + KDRIVE_OS_LIB='$(top_builddir)/kdrive/linux/liblinux.a' + KDRIVELINUX=yes + ;; + esac + KDRIVE_STUB_LIB='$(top_builddir)/kdrive/src/libkdrivestubs.a' + KDRIVE_LIBS="$DIX_LIB $KDRIVE_LIB $KDRIVE_OS_LIB $KDRIVE_PURE_LIBS $KDRIVE_STUB_LIB" +fi +AC_SUBST(KDRIVE_INCS) +AC_SUBST(KDRIVE_PURE_INCS) +AC_SUBST(KDRIVE_CFLAGS) +AC_SUBST(KDRIVE_PURE_LIBS) +AC_SUBST(KDRIVE_LIBS) +AM_CONDITIONAL(KDRIVELINUX, [test "x$KDRIVELINUX" = xyes]) +AM_CONDITIONAL(KDRIVEVESA, [test x"$ac_cv_header_asm_vm86_h" = xyes]) +AM_CONDITIONAL(KDRIVEFBDEV, [test x"$ac_cv_header_linux_fb_h" = xyes]) + +dnl and the rest of these are generic, so they're in config.h +AC_DEFINE(XResExtension, 1, [Build XRes extension]) + +AC_TRY_COMPILE([ +#include +#ifndef __GLIBC__ +#error not glibc +#endif +], [], [AC_DEFINE(_GNU_SOURCE, 1, + [ Enable GNU and other extensions to the C environment for glibc])]) + +dnl ---------- Compiler arguments + +AX_CHECK_COMPILE_FLAG([-flto], + [CFLAGS="$CFLAGS -flto"; LDFLAGS="$LDFLAGS -flto"; ac_cv_lto_supported=yes], + [ac_cv_lto_supported=no], + []) + +if test x"$ac_cv_lto_supported" = xno; then + AC_MSG_NOTICE([LTO not supported, checking sections instead...]) + + AX_CHECK_COMPILE_FLAG([-ffunction-sections], + [CFLAGS="$CFLAGS -ffunction-sections -fdata-sections" + LDFLAGS="$LDFLAGS -Wl,-gc-sections" + ac_cv_sections_supported=yes], + [ac_cv_sections_supported=no], + []) +fi + +AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], + [CFLAGS="$CFLAGS -fvisibility=hidden"; ac_cv_visibility_supported=yes], + [ac_cv_visiblity_supported=no], + []) + +AX_CHECK_LINK_FLAG([-Wl,-as-needed], [LDFLAGS="$LDFLAGS -Wl,-as-needed"], + [], []) + +dnl ---------- + +AC_CHECK_LIB([ife],[meaning]) + +CFLAGS="$XSERVER_CFLAGS $CFLAGS -Wall" +AC_SUBST([CFLAGS]) + +LDFLAGS="$LDFLAGS -Wl,-O1" +AC_SUBST([LDFLAGS]) + +BUILD_DATE="$(date +'%Y%m%d')" +AC_SUBST([BUILD_DATE]) + +DIX_CFLAGS="-DHAVE_DIX_CONFIG_H" +AC_SUBST([DIX_CFLAGS]) + +AC_SUBST([libdir]) +AC_SUBST([exec_prefix]) +AC_SUBST([prefix]) + +# XORG in this case refers to the roll-up releases, not the Xorg DDX. +XORG_RELEASE_VERSION + +AC_OUTPUT([ +Makefile +include/Makefile +damageext/Makefile +dbe/Makefile +dix/Makefile +fb/Makefile +mi/Makefile +miext/Makefile +miext/damage/Makefile +miext/shadow/Makefile +os/Makefile +randr/Makefile +render/Makefile +Xext/Makefile +xfixes/Makefile +kdrive/Makefile +kdrive/fbdev/Makefile +kdrive/linux/Makefile +kdrive/src/Makefile +kdrive/vesa/Makefile +]) diff --git a/damageext/Makefile.am b/damageext/Makefile.am new file mode 100644 index 0000000..35f7620 --- /dev/null +++ b/damageext/Makefile.am @@ -0,0 +1,8 @@ +noinst_LTLIBRARIES = libdamageext.la + +AM_CFLAGS = $(DIX_CFLAGS) + +libdamageext_la_SOURCES = \ + damageext.c \ + damageext.h \ + damageextint.h diff --git a/damageext/damageext.c b/damageext/damageext.c new file mode 100644 index 0000000..3c34ebc --- /dev/null +++ b/damageext/damageext.c @@ -0,0 +1,515 @@ +/* + * Copyright © 2002 Keith Packard + * + * 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 both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "damageextint.h" +#include "extinit.h" + +unsigned char DamageReqCode; + +int DamageEventBase; + +int DamageErrorBase; + +int DamageClientPrivateIndex; + +RESTYPE DamageExtType; + +RESTYPE DamageExtWinType; + +/* Version of the damage extension supported by the server, as opposed to the + * DAMAGE_* defines from damageproto for what version the proto header + * supports. + */ +#define SERVER_DAMAGE_MAJOR 1 +#define SERVER_DAMAGE_MINOR 1 + +#define prScreen screenInfo.screens[0] + +static void +DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) +{ + ClientPtr pClient = pDamageExt->pClient; + DamageClientPtr pDamageClient = GetDamageClient(pClient); + DrawablePtr pDrawable = pDamageExt->pDrawable; + xDamageNotifyEvent ev; + int i; + + UpdateCurrentTimeIf(); + ev = (xDamageNotifyEvent) { + .type = DamageEventBase + XDamageNotify, + .level = pDamageExt->level, + .drawable = pDamageExt->drawable, + .damage = pDamageExt->id, + .timestamp = currentTime.milliseconds, + .geometry.x = pDrawable->x, + .geometry.y = pDrawable->y, + .geometry.width = pDrawable->width, + .geometry.height = pDrawable->height + }; + if (pBoxes) { + for (i = 0; i < nBoxes; i++) { + ev.level = pDamageExt->level; + if (i < nBoxes - 1) + ev.level |= DamageNotifyMore; + ev.area.x = pBoxes[i].x1; + ev.area.y = pBoxes[i].y1; + ev.area.width = pBoxes[i].x2 - pBoxes[i].x1; + ev.area.height = pBoxes[i].y2 - pBoxes[i].y1; + WriteEventsToClient(pClient, 1, (xEvent *) &ev); + } + } + else { + ev.area.x = 0; + ev.area.y = 0; + ev.area.width = pDrawable->width; + ev.area.height = pDrawable->height; + WriteEventsToClient(pClient, 1, (xEvent *) &ev); + } + /* Composite extension marks clients with manual Subwindows as critical */ + if (pDamageClient->critical > 0) { + SetCriticalOutputPending(); + pClient->smart_priority = SMART_MAX_PRIORITY; + } +} + +static void +DamageExtReport(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + switch (pDamageExt->level) { + case DamageReportRawRegion: + case DamageReportDeltaRegion: + DamageExtNotify(pDamageExt, REGION_RECTS(pRegion), + REGION_NUM_RECTS(pRegion)); + break; + case DamageReportBoundingBox: + DamageExtNotify(pDamageExt, REGION_EXTENTS(pRegion), 1); + break; + case DamageReportNonEmpty: + DamageExtNotify(pDamageExt, NullBox, 0); + break; + case DamageReportNone: + break; + } +} + +static void +DamageExtDestroy(DamagePtr pDamage, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + pDamageExt->pDamage = 0; + if (pDamageExt->id) + FreeResource(pDamageExt->id, RT_NONE); +} + +void +DamageExtSetCritical(ClientPtr pClient, Bool critical) +{ + DamageClientPtr pDamageClient = GetDamageClient(pClient); + + if (pDamageClient) + pDamageClient->critical += critical ? 1 : -1; +} + +static int +ProcDamageQueryVersion(ClientPtr client) +{ + DamageClientPtr pDamageClient = GetDamageClient(client); + + xDamageQueryVersionReply rep; + + + REQUEST(xDamageQueryVersionReq); + + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < SERVER_DAMAGE_MAJOR) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } + else { + rep.majorVersion = SERVER_DAMAGE_MAJOR; + if (stuff->majorVersion == SERVER_DAMAGE_MAJOR && + stuff->minorVersion < SERVER_DAMAGE_MINOR) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = SERVER_DAMAGE_MINOR; + } + pDamageClient->major_version = rep.majorVersion; + pDamageClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.majorVersion); + swapl(&rep.minorVersion); + } + WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *) &rep); + return (client->noClientException); +} + +static int +ProcDamageCreate(ClientPtr client) +{ + DrawablePtr pDrawable; + DamageExtPtr pDamageExt; + DamageReportLevel level; + RegionPtr pRegion; + + REQUEST(xDamageCreateReq); + + REQUEST_SIZE_MATCH(xDamageCreateReq); + LEGAL_NEW_RESOURCE(stuff->damage, client); + SECURITY_VERIFY_DRAWABLE(pDrawable, stuff->drawable, client, + SecurityReadAccess); + switch (stuff->level) { + case XDamageReportRawRectangles: + level = DamageReportRawRegion; + break; + case XDamageReportDeltaRectangles: + level = DamageReportDeltaRegion; + break; + case XDamageReportBoundingBox: + level = DamageReportBoundingBox; + break; + case XDamageReportNonEmpty: + level = DamageReportNonEmpty; + break; + default: + client->errorValue = stuff->level; + return BadValue; + } + + pDamageExt = malloc(sizeof(DamageExtRec)); + if (!pDamageExt) + return BadAlloc; + pDamageExt->id = stuff->damage; + pDamageExt->pDrawable = pDrawable; + pDamageExt->level = level; + pDamageExt->pClient = client; + pDamageExt->pDamage = DamageCreate(DamageExtReport, + DamageExtDestroy, + level, + FALSE, pDrawable->pScreen, pDamageExt); + if (!pDamageExt->pDamage) { + free(pDamageExt); + return BadAlloc; + } + if (!AddResource(stuff->damage, DamageExtType, (pointer) pDamageExt)) + return BadAlloc; + + DamageRegister(pDamageExt->pDrawable, pDamageExt->pDamage); + + if (pDrawable->type == DRAWABLE_WINDOW) { + pRegion = &((WindowPtr) pDrawable)->borderClip; + DamageDamageRegion(pDrawable, pRegion); + } + + return (client->noClientException); +} + +static int +ProcDamageDestroy(ClientPtr client) +{ + REQUEST(xDamageDestroyReq); + DamageExtPtr pDamageExt; + + REQUEST_SIZE_MATCH(xDamageDestroyReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); + FreeResource(stuff->damage, RT_NONE); + return (client->noClientException); +} + +static int +ProcDamageSubtract(ClientPtr client) +{ + REQUEST(xDamageSubtractReq); + DamageExtPtr pDamageExt; + + RegionPtr pRepair; + + RegionPtr pParts; + + REQUEST_SIZE_MATCH(xDamageSubtractReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); + VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, SecurityWriteAccess); + VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, SecurityWriteAccess); + + if (pDamageExt->level != DamageReportRawRegion) { + DamagePtr pDamage = pDamageExt->pDamage; + + if (pRepair) { + if (pParts) + REGION_INTERSECT(pParts, DamageRegion(pDamage), + pRepair); + if (DamageSubtract(pDamage, pRepair)) + DamageExtReport(pDamage, DamageRegion(pDamage), + (void *) pDamageExt); + } + else { + if (pParts) + REGION_COPY(pParts, DamageRegion(pDamage)); + DamageEmpty(pDamage); + } + } + return (client->noClientException); +} + +static int +ProcDamageAdd(ClientPtr client) +{ + REQUEST(xDamageAddReq); + DrawablePtr pDrawable; + + RegionPtr pRegion; + + REQUEST_SIZE_MATCH(xDamageAddReq); + VERIFY_REGION(pRegion, stuff->region, client, SecurityWriteAccess); + SECURITY_VERIFY_DRAWABLE(pDrawable, stuff->drawable, client, + SecurityReadAccess); + + /* The region is relative to the drawable origin, so translate it out to + * screen coordinates like damage expects. + */ + REGION_TRANSLATE(pRegion, pDrawable->x, pDrawable->y); + DamageDamageRegion(pDrawable, pRegion); + REGION_TRANSLATE(pRegion, -pDrawable->x, -pDrawable->y); + + return (client->noClientException); +} + +/* Major version controls available requests */ +static const int version_requests[] = { + X_DamageQueryVersion, /* before client sends QueryVersion */ + X_DamageAdd, /* Version 1 */ +}; + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = { +/*************** Version 1 ******************/ + ProcDamageQueryVersion, + ProcDamageCreate, ProcDamageDestroy, ProcDamageSubtract, +/*************** Version 1.1 ****************/ +ProcDamageAdd,}; + +static int +ProcDamageDispatch(ClientPtr client) +{ + REQUEST(xDamageReq); + DamageClientPtr pDamageClient = GetDamageClient(client); + + if (pDamageClient->major_version >= NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->damageReqType > version_requests[pDamageClient->major_version]) + return BadRequest; + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageQueryVersion(ClientPtr client) +{ + + REQUEST(xDamageQueryVersionReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + swapl(&stuff->majorVersion); + swapl(&stuff->minorVersion); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageCreate(ClientPtr client) +{ + + REQUEST(xDamageCreateReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDamageCreateReq); + swapl(&stuff->damage); + swapl(&stuff->drawable); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageDestroy(ClientPtr client) +{ + + REQUEST(xDamageDestroyReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDamageDestroyReq); + swapl(&stuff->damage); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageSubtract(ClientPtr client) +{ + + REQUEST(xDamageSubtractReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDamageSubtractReq); + swapl(&stuff->damage); + swapl(&stuff->repair); + swapl(&stuff->parts); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageAdd(ClientPtr client) +{ + + REQUEST(xDamageAddReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDamageSubtractReq); + swapl(&stuff->drawable); + swapl(&stuff->region); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = { +/*************** Version 1 ******************/ + SProcDamageQueryVersion, + SProcDamageCreate, SProcDamageDestroy, SProcDamageSubtract, +/*************** Version 1.1 ****************/ +SProcDamageAdd,}; + +static int +SProcDamageDispatch(ClientPtr client) +{ + REQUEST(xDamageReq); + if (stuff->damageReqType >= XDamageNumberRequests) + return BadRequest; + return (*SProcDamageVector[stuff->damageReqType]) (client); +} + +static void +DamageClientCallback(CallbackListPtr *list, pointer closure, pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + DamageClientPtr pDamageClient = GetDamageClient(pClient); + + pDamageClient->critical = 0; + pDamageClient->major_version = 0; + pDamageClient->minor_version = 0; +} + + /*ARGSUSED*/ static void +DamageResetProc(ExtensionEntry * extEntry) +{ + DeleteCallback(&ClientStateCallback, DamageClientCallback, 0); +} + +static int +FreeDamageExt(pointer value, XID did) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + /* + * Get rid of the resource table entry hanging from the window id + */ + pDamageExt->id = 0; + if (WindowDrawable(pDamageExt->pDrawable->type)) + FreeResourceByType(pDamageExt->pDrawable->id, DamageExtWinType, TRUE); + if (pDamageExt->pDamage) { + DamageUnregister(pDamageExt->pDrawable, pDamageExt->pDamage); + DamageDestroy(pDamageExt->pDamage); + } + free(pDamageExt); + return Success; +} + +static int +FreeDamageExtWin(pointer value, XID wid) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + if (pDamageExt->id) + FreeResource(pDamageExt->id, RT_NONE); + return Success; +} + +void +SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to) +{ + to->type = from->type; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->drawable, to->drawable); + cpswapl(from->damage, to->damage); + cpswaps(from->area.x, to->area.x); + cpswaps(from->area.y, to->area.y); + cpswaps(from->area.width, to->area.width); + cpswaps(from->area.height, to->area.height); + cpswaps(from->geometry.x, to->geometry.x); + cpswaps(from->geometry.y, to->geometry.y); + cpswaps(from->geometry.width, to->geometry.width); + cpswaps(from->geometry.height, to->geometry.height); +} + +void +DamageExtensionInit(void) +{ + ExtensionEntry *extEntry; + + int s; + + for (s = 0; s < screenInfo.numScreens; s++) + DamageSetup(screenInfo.screens[s]); + + DamageExtType = CreateNewResourceType(FreeDamageExt); + if (!DamageExtType) + return; + + DamageExtWinType = CreateNewResourceType(FreeDamageExtWin); + if (!DamageExtWinType) + return; + + DamageClientPrivateIndex = AllocateClientPrivateIndex(); + if (!AllocateClientPrivate(DamageClientPrivateIndex, + sizeof(DamageClientRec))) + return; + if (!AddCallback(&ClientStateCallback, DamageClientCallback, 0)) + return; + + if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents, + XDamageNumberErrors, + ProcDamageDispatch, SProcDamageDispatch, + DamageResetProc, StandardMinorOpcode)) != 0) { + DamageReqCode = (unsigned char) extEntry->base; + DamageEventBase = extEntry->eventBase; + DamageErrorBase = extEntry->errorBase; + EventSwapVector[DamageEventBase + XDamageNotify] = + (EventSwapPtr) SDamageNotifyEvent; + } +} diff --git a/damageext/damageext.h b/damageext/damageext.h new file mode 100644 index 0000000..bd99635 --- /dev/null +++ b/damageext/damageext.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2002 Keith Packard + * + * 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 both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef _DAMAGEEXT_H_ +#define _DAMAGEEXT_H_ + +void + DamageExtensionInit(void); + +#endif /* _DAMAGEEXT_H_ */ diff --git a/damageext/damageextint.h b/damageext/damageextint.h new file mode 100644 index 0000000..e7beb36 --- /dev/null +++ b/damageext/damageextint.h @@ -0,0 +1,91 @@ +/* + * Copyright © 2002 Keith Packard + * + * 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 both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef _DAMAGEEXTINT_H_ +#define _DAMAGEEXTINT_H_ + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include +#include "windowstr.h" +#include "selection.h" +#include "scrnintstr.h" +#include "damageext.h" +#include "damage.h" +#include "xfixes.h" + +extern unsigned char DamageReqCode; + +extern int DamageEventBase; + +extern int DamageErrorBase; + +extern int DamageClientPrivateIndex; + +extern RESTYPE DamageExtType; + +extern RESTYPE DamageExtWinType; + +typedef struct _DamageClient { + CARD32 major_version; + CARD32 minor_version; + int critical; +} DamageClientRec, *DamageClientPtr; + +#define GetDamageClient(pClient) ((DamageClientPtr) (pClient)->devPrivates[DamageClientPrivateIndex].ptr) + +typedef struct _DamageExt { + DamagePtr pDamage; + DrawablePtr pDrawable; + DamageReportLevel level; + ClientPtr pClient; + XID id; + XID drawable; +} DamageExtRec, *DamageExtPtr; + +extern int (*ProcDamageVector[ /*XDamageNumberRequests */ ]) (ClientPtr); + +extern int (*SProcDamageVector[ /*XDamageNumberRequests */ ]) (ClientPtr); + +#define VERIFY_DAMAGEEXT(pDamageExt, rid, client, mode) { \ + pDamageExt = SecurityLookupIDByType (client, rid, DamageExtType, mode); \ + if (!pDamageExt) { \ + client->errorValue = rid; \ + return DamageErrorBase + BadDamage; \ + } \ +} + +void + SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to); + +void + DamageExtSetCritical(ClientPtr pClient, Bool critical); + +#endif /* _DAMAGEEXTINT_H_ */ diff --git a/dbe/Makefile.am b/dbe/Makefile.am new file mode 100644 index 0000000..d609996 --- /dev/null +++ b/dbe/Makefile.am @@ -0,0 +1,10 @@ +noinst_LTLIBRARIES = libdbe.la + +AM_CFLAGS = $(DIX_CFLAGS) + +libdbe_la_SOURCES = \ + dbe.c \ + dbestruct.h \ + midbe.c \ + midbe.h \ + midbestr.h diff --git a/dbe/dbe.c b/dbe/dbe.c new file mode 100644 index 0000000..2e945be --- /dev/null +++ b/dbe/dbe.c @@ -0,0 +1,1829 @@ +/****************************************************************************** + * + * Copyright (c) 1994, 1995 Hewlett-Packard Company + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the Hewlett-Packard + * Company shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the Hewlett-Packard Company. + * + * DIX DBE code + * + *****************************************************************************/ + +/* INCLUDES */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "scrnintstr.h" +#include "extnsionst.h" +#include "extinit.h" +#include "gcstruct.h" +#include "dixstruct.h" +#define NEED_DBE_PROTOCOL +#include "dbestruct.h" +#include "midbe.h" + +/* GLOBALS */ + +/* Per-screen initialization functions [init'ed by DbeRegisterFunction()] */ +static Bool (*DbeInitFunct[MAXSCREENS]) (); /* pScreen, pDbeScreenPriv */ + +/* These are static globals copied to DBE's screen private for use by DDX */ +static int dbeScreenPrivIndex; + +static int dbeWindowPrivIndex; + +/* These are static globals copied to DBE's screen private for use by DDX */ +static RESTYPE dbeDrawableResType; + +static RESTYPE dbeWindowPrivResType; + +/* This global is used by DbeAllocWinPrivPrivIndex() */ +static int winPrivPrivCount = 0; + +/* Used to generate DBE's BadBuffer error. */ +static int dbeErrorBase; + +/* Used by DbeRegisterFunction() to initialize the initialization function + * table only once per server lifetime. + */ +static Bool firstRegistrationPass = TRUE; + +/****************************************************************************** + * + * DBE DIX Procedure: DbeValidateBuffer + * + * Description: + * + * This function is called from VALIDATE_DRAWABLE_AND_GC and from + * various places in dispatch.c if the server has been compiled with + * the flags -DNEED_DBE_BUF_BITS and -DNEED_DBE_BUF_VALIDATE. + * When pWin->dstBuffer changes, this function will be called with pWin + * as the first argument, the drawable ID that was specified as the + * second argument (could be a back buffer id), and True for the third + * argument. + * When pWin->srcBuffer changes, the third argument will be False, and + * the first two arguments are as described for dstBuffer. + * + * This function should prepare the hardware to access the specified + * buffer for reads (if dstbuf is False) or writes (if dstbuf is True). + * + *****************************************************************************/ + +void +DbeValidateBuffer(WindowPtr pWin, XID drawID, Bool dstbuf) +{ + DbeScreenPrivPtr pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(pWin); + + if (pDbeScreenPriv->ValidateBuffer) + (*pDbeScreenPriv->ValidateBuffer) (pWin, drawID, dstbuf); +} + +/****************************************************************************** + * + * DBE DIX Procedure: DbeRegisterFunction + * + * Description: + * + * This function registers the DBE init function for the specified screen. + * + *****************************************************************************/ + +void +DbeRegisterFunction(ScreenPtr pScreen, Bool (*funct) ( /* ??? */ )) +{ + int i; + + /* Initialize the initialization function table if it has not been + * initialized already. + */ + if (firstRegistrationPass) { + for (i = 0; i < MAXSCREENS; i++) { + DbeInitFunct[i] = NULL; + } + + firstRegistrationPass = FALSE; + } + + DbeInitFunct[pScreen->myNum] = funct; + +} /* DbeRegisterFunction() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeAllocWinPriv + * + * Description: + * + * This function was cloned from AllocateWindow() in window.c. + * This function allocates a window priv structure to be associated + * with a double-buffered window. + * + *****************************************************************************/ +static DbeWindowPrivPtr +DbeAllocWinPriv(ScreenPtr pScreen) +{ + DbeWindowPrivPtr pDbeWindowPriv; + + DbeScreenPrivPtr pDbeScreenPriv; + + char *ptr; + + DevUnion *ppriv; + + unsigned int *sizes; + + unsigned int size; + + int i; + + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + pDbeWindowPriv = + malloc(pDbeScreenPriv->totalWinPrivSize); + + if (pDbeWindowPriv) { + ppriv = (DevUnion *) (pDbeWindowPriv + 1); + pDbeWindowPriv->devPrivates = ppriv; + sizes = pDbeScreenPriv->winPrivPrivSizes; + ptr = (char *) (ppriv + pDbeScreenPriv->winPrivPrivLen); + for (i = pDbeScreenPriv->winPrivPrivLen; --i >= 0; ppriv++, sizes++) { + if ((size = *sizes)) { + ppriv->ptr = (pointer) ptr; + ptr += size; + } + else + ppriv->ptr = (pointer) NULL; + } + } + + return (pDbeWindowPriv); + +} /* DbeAllocWinPriv() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeFallbackAllocWinPriv + * + * Description: + * + * This is a fallback function for AllocWinPriv(). + * + *****************************************************************************/ + +#if 0 /* NOT USED */ +static DbeWindowPrivPtr +DbeFallbackAllocWinPriv(pScreen) +ScreenPtr pScreen; +{ + return (NULL); +} /* DbeFallbackAllocWinPriv() */ +#endif + +/****************************************************************************** + * + * DBE DIX Procedure: DbeAllocWinPrivPrivIndex + * + * Description: + * + * This function was cloned from AllocateWindowPrivateIndex() in window.c. + * This function allocates a new window priv priv index by simply returning + * an incremented private counter. + * + *****************************************************************************/ + +static int +DbeAllocWinPrivPrivIndex(void) +{ + return winPrivPrivCount++; + +} /* DbeAllocWinPrivPrivIndex() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeAllocWinPrivPriv + * + * Description: + * + * This function was cloned from AllocateWindowPrivate() in privates.c. + * This function allocates a private structure to be hung off + * a window private. + * + *****************************************************************************/ + +static Bool +DbeAllocWinPrivPriv(register ScreenPtr pScreen, int index, unsigned int amount) +{ + DbeScreenPrivPtr pDbeScreenPriv; + + unsigned int oldamount; + + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + if (index >= pDbeScreenPriv->winPrivPrivLen) { + unsigned *nsizes; + + nsizes = (unsigned *) realloc(pDbeScreenPriv->winPrivPrivSizes, + (index + 1) * sizeof(unsigned)); + if (!nsizes) { + return (FALSE); + } + + while (pDbeScreenPriv->winPrivPrivLen <= index) { + nsizes[pDbeScreenPriv->winPrivPrivLen++] = 0; + pDbeScreenPriv->totalWinPrivSize += sizeof(DevUnion); + } + + pDbeScreenPriv->winPrivPrivSizes = nsizes; + } + + oldamount = pDbeScreenPriv->winPrivPrivSizes[index]; + + if (amount > oldamount) { + pDbeScreenPriv->winPrivPrivSizes[index] = amount; + pDbeScreenPriv->totalWinPrivSize += (amount - oldamount); + } + return (TRUE); + +} /* DbeAllocWinPrivPriv() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeStubScreen + * + * Description: + * + * This is function stubs the function pointers in the given DBE screen + * private and increments the number of stubbed screens. + * + *****************************************************************************/ + +static void +DbeStubScreen(DbeScreenPrivPtr pDbeScreenPriv, int *nStubbedScreens) +{ + /* Stub DIX. */ + pDbeScreenPriv->SetupBackgroundPainter = NULL; + pDbeScreenPriv->AllocWinPriv = NULL; + pDbeScreenPriv->AllocWinPrivPrivIndex = NULL; + pDbeScreenPriv->AllocWinPrivPriv = NULL; + + /* Do not unwrap PositionWindow nor DestroyWindow. If the DDX + * initialization function failed, we assume that it did not wrap + * PositionWindow. Also, DestroyWindow is only wrapped if the DDX + * initialization function succeeded. + */ + + /* Stub DDX. */ + pDbeScreenPriv->GetVisualInfo = NULL; + pDbeScreenPriv->AllocBackBufferName = NULL; + pDbeScreenPriv->SwapBuffers = NULL; + pDbeScreenPriv->BeginIdiom = NULL; + pDbeScreenPriv->EndIdiom = NULL; + pDbeScreenPriv->WinPrivDelete = NULL; + pDbeScreenPriv->ResetProc = NULL; + pDbeScreenPriv->ValidateBuffer = NULL; + + (*nStubbedScreens)++; + +} /* DbeStubScreen() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeGetVersion + * + * Description: + * + * This function is for processing a DbeGetVersion request. + * This request returns the major and minor version numbers of this + * extension. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +ProcDbeGetVersion(ClientPtr client) +{ + /* REQUEST(xDbeGetVersionReq); */ + xDbeGetVersionReply rep; + + + REQUEST_SIZE_MATCH(xDbeGetVersionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = DBE_MAJOR_VERSION; + rep.minorVersion = DBE_MINOR_VERSION; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + } + + WriteToClient(client, sizeof(xDbeGetVersionReply), (char *) &rep); + + return (client->noClientException); + +} /* ProcDbeGetVersion() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeAllocateBackBufferName + * + * Description: + * + * This function is for processing a DbeAllocateBackBufferName request. + * This request allocates a drawable ID used to refer to the back buffer + * of a window. + * + * Return Values: + * + * BadAlloc - server can not allocate resources + * BadIDChoice - id is out of range for client; id is already in use + * BadMatch - window is not an InputOutput window; + * visual of window is not on list returned by + * DBEGetVisualInfo; + * BadValue - invalid swap action is specified + * BadWindow - window is not a valid window + * Success + * + *****************************************************************************/ + +static int +ProcDbeAllocateBackBufferName(ClientPtr client) +{ + REQUEST(xDbeAllocateBackBufferNameReq); + WindowPtr pWin; + DbeScreenPrivPtr pDbeScreenPriv; + DbeWindowPrivPtr pDbeWindowPriv; + XdbeScreenVisualInfo scrVisInfo; + int i; + Bool visualMatched = FALSE; + xDbeSwapAction swapAction; + VisualID visual; + int status; + + REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); + + /* The window must be valid. */ + if (!(pWin = SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess))) { + return (BadWindow); + } + + /* The window must be InputOutput. */ + if (pWin->drawable.class != InputOutput) { + return BadMatch; + } + + /* The swap action must be valid. */ + swapAction = stuff->swapAction; /* use local var for performance. */ + if ((swapAction != XdbeUndefined) && + (swapAction != XdbeBackground) && + (swapAction != XdbeUntouched) && (swapAction != XdbeCopied)) { + return BadValue; + } + + /* The id must be in range and not already in use. */ + LEGAL_NEW_RESOURCE(stuff->buffer, client); + + /* The visual of the window must be in the list returned by + * GetVisualInfo. + */ + pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(pWin); + if (!pDbeScreenPriv->GetVisualInfo) + return BadMatch; /* screen doesn't support double buffering */ + + if (!(*pDbeScreenPriv->GetVisualInfo) (pWin->drawable.pScreen, &scrVisInfo)) { + /* GetVisualInfo() failed to allocate visual info data. */ + return BadAlloc; + } + + /* See if the window's visual is on the list. */ + visual = wVisual(pWin); + for (i = 0; (i < scrVisInfo.count) && !visualMatched; i++) { + if (scrVisInfo.visinfo[i].visual == visual) { + visualMatched = TRUE; + } + } + + /* Free what was allocated by the GetVisualInfo() call above. */ + free(scrVisInfo.visinfo); + + if (!visualMatched) { + return BadMatch; + } + + if ((pDbeWindowPriv = DBE_WINDOW_PRIV(pWin)) == NULL) { + /* There is no buffer associated with the window. + * Allocate a window priv. + */ + + if (!(pDbeWindowPriv = + (*pDbeScreenPriv->AllocWinPriv) (pWin->drawable.pScreen))) { + return (BadAlloc); + } + + /* Make the window priv a DBE window priv resource. */ + if (!AddResource(stuff->buffer, dbeWindowPrivResType, + (pointer) pDbeWindowPriv)) { + free(pDbeWindowPriv); + return (BadAlloc); + } + + /* Fill out window priv information. */ + pDbeWindowPriv->pWindow = pWin; + pDbeWindowPriv->width = pWin->drawable.width; + pDbeWindowPriv->height = pWin->drawable.height; + pDbeWindowPriv->x = pWin->drawable.x; + pDbeWindowPriv->y = pWin->drawable.y; + pDbeWindowPriv->nBufferIDs = 0; + + /* Set the buffer ID array pointer to the initial (static) array). */ + pDbeWindowPriv->IDs = pDbeWindowPriv->initIDs; + + /* Initialize the buffer ID list. */ + pDbeWindowPriv->maxAvailableIDs = DBE_INIT_MAX_IDS; + pDbeWindowPriv->IDs[0] = stuff->buffer; + for (i = 1; i < DBE_INIT_MAX_IDS; i++) { + pDbeWindowPriv->IDs[i] = DBE_FREE_ID_ELEMENT; + } + + /* Actually connect the window priv to the window. */ + pWin->devPrivates[dbeWindowPrivIndex].ptr = (pointer) pDbeWindowPriv; + + } /* if -- There is no buffer associated with the window. */ + + else { + /* A buffer is already associated with the window. + * Add the new buffer ID to the array, reallocating the array memory + * if necessary. + */ + + /* Determine if there is a free element in the ID array. */ + for (i = 0; i < pDbeWindowPriv->maxAvailableIDs; i++) { + if (pDbeWindowPriv->IDs[i] == DBE_FREE_ID_ELEMENT) { + /* There is still room in the ID array. */ + break; + } + } + + if (i == pDbeWindowPriv->maxAvailableIDs) { + /* No more room in the ID array -- reallocate another array. */ + XID *pIDs; + + /* Setup an array pointer for the realloc operation below. */ + if (pDbeWindowPriv->maxAvailableIDs == DBE_INIT_MAX_IDS) { + /* We will malloc a new array. */ + pIDs = NULL; + } + else { + /* We will realloc a new array. */ + pIDs = pDbeWindowPriv->IDs; + } + + /* malloc/realloc a new array and initialize all elements to 0. */ + pDbeWindowPriv->IDs = (XID *) realloc(pIDs, + (pDbeWindowPriv-> + maxAvailableIDs + + DBE_INCR_MAX_IDS) * + sizeof(XID)); + if (!pDbeWindowPriv->IDs) { + return BadAlloc; + } + memset(&pDbeWindowPriv->IDs[pDbeWindowPriv->nBufferIDs], 0, + (pDbeWindowPriv->maxAvailableIDs + DBE_INCR_MAX_IDS - + pDbeWindowPriv->nBufferIDs) * sizeof(XID)); + + if (pDbeWindowPriv->maxAvailableIDs == DBE_INIT_MAX_IDS) { + /* We just went from using the initial (static) array to a + * newly allocated array. Copy the IDs from the initial array + * to the new array. + */ + memcpy(pDbeWindowPriv->IDs, pDbeWindowPriv->initIDs, + DBE_INIT_MAX_IDS * sizeof(XID)); + } + + pDbeWindowPriv->maxAvailableIDs += DBE_INCR_MAX_IDS; + } + + /* Finally, record the buffer ID in the array. */ + pDbeWindowPriv->IDs[i] = stuff->buffer; + + /* Associate the new ID with an existing window priv. */ + if (!AddResource(stuff->buffer, dbeWindowPrivResType, + (pointer) pDbeWindowPriv)) { + pDbeWindowPriv->IDs[i] = DBE_FREE_ID_ELEMENT; + return (BadAlloc); + } + + } /* else -- A buffer is already associated with the window. */ + + /* Call the DDX routine to allocate the back buffer. */ + status = (*pDbeScreenPriv->AllocBackBufferName) (pWin, stuff->buffer, + stuff->swapAction); + + if ((status != Success) && (pDbeWindowPriv->nBufferIDs == 0)) { + /* The DDX buffer allocation routine failed for the first buffer of + * this window. + */ + free(pDbeWindowPriv); + return (status); + } + + /* Increment the number of buffers (XIDs) associated with this window. */ + pDbeWindowPriv->nBufferIDs++; + + /* Set swap action on all calls. */ + pDbeWindowPriv->swapAction = stuff->swapAction; + + return (status); + +} /* ProcDbeAllocateBackBufferName() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeDeallocateBackBufferName + * + * Description: + * + * This function is for processing a DbeDeallocateBackBufferName request. + * This request frees a drawable ID that was obtained by a + * DbeAllocateBackBufferName request. + * + * Return Values: + * + * BadBuffer - buffer to deallocate is not associated with a window + * Success + * + *****************************************************************************/ + +static int +ProcDbeDeallocateBackBufferName(ClientPtr client) +{ + REQUEST(xDbeDeallocateBackBufferNameReq); + DbeWindowPrivPtr pDbeWindowPriv; + + int i; + + REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); + + /* Buffer name must be valid */ + if (!(pDbeWindowPriv = (DbeWindowPrivPtr) SecurityLookupIDByType(client, + stuff-> + buffer, + dbeWindowPrivResType, + SecurityDestroyAccess)) + || + !(SecurityLookupIDByType + (client, stuff->buffer, dbeDrawableResType, SecurityDestroyAccess))) { + client->errorValue = stuff->buffer; + return (dbeErrorBase + DbeBadBuffer); + } + + /* Make sure that the id is valid for the window. + * This is paranoid code since we already looked up the ID by type + * above. + */ + + for (i = 0; i < pDbeWindowPriv->nBufferIDs; i++) { + /* Loop through the ID list to find the ID. */ + if (pDbeWindowPriv->IDs[i] == stuff->buffer) { + break; + } + } + + if (i == pDbeWindowPriv->nBufferIDs) { + /* We did not find the ID in the ID list. */ + client->errorValue = stuff->buffer; + return dbeErrorBase + DbeBadBuffer; + } + + FreeResource(stuff->buffer, RT_NONE); + + return Success; + +} /* ProcDbeDeallocateBackBufferName() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeSwapBuffers + * + * Description: + * + * This function is for processing a DbeSwapBuffers request. + * This request swaps the buffers for all windows listed, applying the + * appropriate swap action for each window. + * + * Return Values: + * + * BadAlloc - local allocation failed; this return value is not defined + * by the protocol + * BadMatch - a window in request is not double-buffered; a window in + * request is listed more than once + * BadValue - invalid swap action is specified; no swap action is + * specified + * BadWindow - a window in request is not valid + * Success + * + *****************************************************************************/ + +static int +ProcDbeSwapBuffers(ClientPtr client) +{ + REQUEST(xDbeSwapBuffersReq); + WindowPtr pWin; + DbeScreenPrivPtr pDbeScreenPriv; + DbeSwapInfoPtr swapInfo; + xDbeSwapInfo *dbeSwapInfo; + int error; + int i, j; + int nStuff; + + REQUEST_AT_LEAST_SIZE(xDbeSwapBuffersReq); + nStuff = stuff->n; /* use local variable for performance. */ + + if (nStuff == 0) { + return Success; + } + + if (nStuff > UINT32_MAX / sizeof(DbeSwapInfoRec)) + return BadAlloc; + + /* Get to the swap info appended to the end of the request. */ + dbeSwapInfo = (xDbeSwapInfo *) &stuff[1]; + + /* Allocate array to record swap information. */ + swapInfo = malloc(nStuff * sizeof(DbeSwapInfoRec)); + if (swapInfo == NULL) { + return BadAlloc; + } + + for (i = 0; i < nStuff; i++) { + /* Check all windows to swap. */ + + /* Each window must be a valid window - BadWindow. */ + if (!(pWin = SecurityLookupWindow(dbeSwapInfo[i].window, client, + SecurityWriteAccess))) { + free(swapInfo); + return (BadWindow); + } + + /* Each window must be double-buffered - BadMatch. */ + if (DBE_WINDOW_PRIV(pWin) == NULL) { + free(swapInfo); + return BadMatch; + } + + /* Each window must only be specified once - BadMatch. */ + for (j = i + 1; j < nStuff; j++) { + if (dbeSwapInfo[i].window == dbeSwapInfo[j].window) { + free(swapInfo); + return BadMatch; + } + } + + /* Each swap action must be valid - BadValue. */ + if ((dbeSwapInfo[i].swapAction != XdbeUndefined) && + (dbeSwapInfo[i].swapAction != XdbeBackground) && + (dbeSwapInfo[i].swapAction != XdbeUntouched) && + (dbeSwapInfo[i].swapAction != XdbeCopied)) { + free(swapInfo); + return BadValue; + } + + /* Everything checks out OK. Fill in the swap info array. */ + swapInfo[i].pWindow = pWin; + swapInfo[i].swapAction = dbeSwapInfo[i].swapAction; + + } /* for (i = 0; i < nStuff; i++) */ + + /* Call the DDX routine to perform the swap(s). The DDX routine should + * scan the swap list (swap info), swap any buffers that it knows how to + * handle, delete them from the list, and update nStuff to indicate how + * many windows it did not handle. + * + * This scheme allows a range of sophistication in the DDX SwapBuffers() + * implementation. Naive implementations could just swap the first buffer + * in the list, move the last buffer to the front, decrement nStuff, and + * return. The next level of sophistication could be to scan the whole + * list for windows on the same screen. Up another level, the DDX routine + * could deal with cross-screen synchronization. + */ + + while (nStuff > 0) { + pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(swapInfo[0].pWindow); + error = (*pDbeScreenPriv->SwapBuffers) (client, &nStuff, swapInfo); + if (error != Success) { + free(swapInfo); + return (error); + } + } + + free(swapInfo); + return (Success); + +} /* ProcDbeSwapBuffers() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeBeginIdiom + * + * Description: + * + * This function is for processing a DbeBeginIdiom request. + * This request informs the server that a complex swap will immediately + * follow this request. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +ProcDbeBeginIdiom(ClientPtr client) +{ + /* REQUEST(xDbeBeginIdiomReq); */ + DbeScreenPrivPtr pDbeScreenPriv; + + int i; + + REQUEST_SIZE_MATCH(xDbeBeginIdiomReq); + + for (i = 0; i < screenInfo.numScreens; i++) { + pDbeScreenPriv = DBE_SCREEN_PRIV(screenInfo.screens[i]); + + /* Call the DDX begin idiom procedure if there is one. */ + if (pDbeScreenPriv->BeginIdiom) { + (*pDbeScreenPriv->BeginIdiom) (client); + } + } + + return (Success); + +} /* ProcDbeBeginIdiom() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeGetVisualInfo + * + * Description: + * + * This function is for processing a ProcDbeGetVisualInfo request. + * This request returns information about which visuals support + * double buffering. + * + * Return Values: + * + * BadDrawable - value in screen specifiers is not a valid drawable + * Success + * + *****************************************************************************/ + +static int +ProcDbeGetVisualInfo(ClientPtr client) +{ + REQUEST(xDbeGetVisualInfoReq); + DbeScreenPrivPtr pDbeScreenPriv; + xDbeGetVisualInfoReply rep; + Drawable *drawables; + DrawablePtr *pDrawables = NULL; + int i, j; + int count; /* number of visual infos in reply */ + int length; /* length of reply */ + ScreenPtr pScreen; + XdbeScreenVisualInfo *pScrVisInfo; + + REQUEST_AT_LEAST_SIZE(xDbeGetVisualInfoReq); + + if (stuff->n > UINT32_MAX / sizeof(DrawablePtr)) + return BadAlloc; + /* Make sure any specified drawables are valid. */ + if (stuff->n != 0) { + if (!(pDrawables = malloc(stuff->n * + sizeof(DrawablePtr)))) { + return (BadAlloc); + } + + drawables = (Drawable *) &stuff[1]; + + for (i = 0; i < stuff->n; i++) { + if (! + (pDrawables[i] = + (DrawablePtr) SecurityLookupDrawable(drawables[i], client, + SecurityReadAccess))) { + free(pDrawables); + return (BadDrawable); + } + } + } + + count = (stuff->n == 0) ? screenInfo.numScreens : stuff->n; + if (!(pScrVisInfo = malloc(count * + sizeof + (XdbeScreenVisualInfo)))) + { + if (pDrawables) { + free(pDrawables); + } + + return (BadAlloc); + } + + length = 0; + + for (i = 0; i < count; i++) { + pScreen = (stuff->n == 0) ? screenInfo.screens[i] : + pDrawables[i]->pScreen; + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + if (!(*pDbeScreenPriv->GetVisualInfo) (pScreen, &pScrVisInfo[i])) { + /* We failed to alloc pScrVisInfo[i].visinfo. */ + + /* Free visinfos that we allocated for previous screen infos. */ + for (j = 0; j < i; j++) { + free(pScrVisInfo[j].visinfo); + } + + /* Free pDrawables if we needed to allocate it above. */ + if (pDrawables) { + free(pDrawables); + } + + return (BadAlloc); + } + + /* Account for n, number of xDbeVisInfo items in list. */ + length += sizeof(CARD32); + + /* Account for n xDbeVisInfo items */ + length += pScrVisInfo[i].count * sizeof(xDbeVisInfo); + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = length >> 2; + rep.m = count; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.m); + } + + /* Send off reply. */ + WriteToClient(client, sizeof(xDbeGetVisualInfoReply), (char *) &rep); + + for (i = 0; i < count; i++) { + CARD32 data32; + + /* For each screen in the reply, send off the visual info */ + + /* Send off number of visuals. */ + data32 = (CARD32) pScrVisInfo[i].count; + + if (client->swapped) { + swapl(&data32); + } + + WriteToClient(client, sizeof(CARD32), (char *) &data32); + + /* Now send off visual info items. */ + for (j = 0; j < pScrVisInfo[i].count; j++) { + xDbeVisInfo visInfo; + + /* Copy the data in the client data structure to a protocol + * data structure. We will send data to the client from the + * protocol data structure. + */ + + visInfo.visualID = (CARD32) pScrVisInfo[i].visinfo[j].visual; + visInfo.depth = (CARD8) pScrVisInfo[i].visinfo[j].depth; + visInfo.perfLevel = (CARD8) pScrVisInfo[i].visinfo[j].perflevel; + + if (client->swapped) { + swapl(&visInfo.visualID); + + /* We do not need to swap depth and perfLevel since they are + * already 1 byte quantities. + */ + } + + /* Write visualID(32), depth(8), perfLevel(8), and pad(16). */ + WriteToClient(client, 2 * sizeof(CARD32), + (char *) &visInfo.visualID); + } + } + + /* Clean up memory. */ + for (i = 0; i < count; i++) { + free(pScrVisInfo[i].visinfo); + } + free(pScrVisInfo); + + if (pDrawables) { + free(pDrawables); + } + + return (client->noClientException); + +} /* ProcDbeGetVisualInfo() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeGetbackBufferAttributes + * + * Description: + * + * This function is for processing a ProcDbeGetbackBufferAttributes + * request. This request returns information about a back buffer. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +ProcDbeGetBackBufferAttributes(ClientPtr client) +{ + REQUEST(xDbeGetBackBufferAttributesReq); + xDbeGetBackBufferAttributesReply rep; + + DbeWindowPrivPtr pDbeWindowPriv; + + REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); + + if (!(pDbeWindowPriv = (DbeWindowPrivPtr) SecurityLookupIDByType(client, + stuff-> + buffer, + dbeWindowPrivResType, + SecurityReadAccess))) + { + rep.attributes = None; + } + else { + rep.attributes = pDbeWindowPriv->pWindow->drawable.id; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.attributes); + } + + WriteToClient(client, sizeof(xDbeGetBackBufferAttributesReply), + (char *) &rep); + return (client->noClientException); + +} /* ProcDbeGetbackBufferAttributes() */ + +/****************************************************************************** + * + * DBE DIX Procedure: ProcDbeDispatch + * + * Description: + * + * This function dispatches DBE requests. + * + *****************************************************************************/ + +static int +ProcDbeDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DbeGetVersion: + return (ProcDbeGetVersion(client)); + + case X_DbeAllocateBackBufferName: + return (ProcDbeAllocateBackBufferName(client)); + + case X_DbeDeallocateBackBufferName: + return (ProcDbeDeallocateBackBufferName(client)); + + case X_DbeSwapBuffers: + return (ProcDbeSwapBuffers(client)); + + case X_DbeBeginIdiom: + return Success; + + case X_DbeEndIdiom: + return Success; + + case X_DbeGetVisualInfo: + return (ProcDbeGetVisualInfo(client)); + + case X_DbeGetBackBufferAttributes: + return (ProcDbeGetBackBufferAttributes(client)); + + default: + return BadRequest; + } + +} /* ProcDbeDispatch() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeGetVersion + * + * Description: + * + * This function is for processing a DbeGetVersion request on a swapped + * server. This request returns the major and minor version numbers of + * this extension. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +SProcDbeGetVersion(ClientPtr client) +{ + REQUEST(xDbeGetVersionReq); + + swaps(&stuff->length); + return (ProcDbeGetVersion(client)); + +} /* SProcDbeGetVersion() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeAllocateBackBufferName + * + * Description: + * + * This function is for processing a DbeAllocateBackBufferName request on + * a swapped server. This request allocates a drawable ID used to refer + * to the back buffer of a window. + * + * Return Values: + * + * BadAlloc - server can not allocate resources + * BadIDChoice - id is out of range for client; id is already in use + * BadMatch - window is not an InputOutput window; + * visual of window is not on list returned by + * DBEGetVisualInfo; + * BadValue - invalid swap action is specified + * BadWindow - window is not a valid window + * Success + * + *****************************************************************************/ + +static int +SProcDbeAllocateBackBufferName(ClientPtr client) +{ + REQUEST(xDbeAllocateBackBufferNameReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDbeAllocateBackBufferNameReq); + + swapl(&stuff->window); + swapl(&stuff->buffer); + /* stuff->swapAction is a byte. We do not need to swap this field. */ + + return (ProcDbeAllocateBackBufferName(client)); + +} /* SProcDbeAllocateBackBufferName() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeDeallocateBackBufferName + * + * Description: + * + * This function is for processing a DbeDeallocateBackBufferName request + * on a swapped server. This request frees a drawable ID that was + * obtained by a DbeAllocateBackBufferName request. + * + * Return Values: + * + * BadBuffer - buffer to deallocate is not associated with a window + * Success + * + *****************************************************************************/ + +static int +SProcDbeDeallocateBackBufferName(ClientPtr client) +{ + REQUEST(xDbeDeallocateBackBufferNameReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDbeDeallocateBackBufferNameReq); + + swapl(&stuff->buffer); + + return (ProcDbeDeallocateBackBufferName(client)); + +} /* SProcDbeDeallocateBackBufferName() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeSwapBuffers + * + * Description: + * + * This function is for processing a DbeSwapBuffers request on a swapped + * server. This request swaps the buffers for all windows listed, + * applying the appropriate swap action for each window. + * + * Return Values: + * + * BadMatch - a window in request is not double-buffered; a window in + * request is listed more than once; all windows in request do + * not have the same root + * BadValue - invalid swap action is specified + * BadWindow - a window in request is not valid + * Success + * + *****************************************************************************/ + +static int +SProcDbeSwapBuffers(ClientPtr client) +{ + REQUEST(xDbeSwapBuffersReq); + int i; + + xDbeSwapInfo *pSwapInfo; + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xDbeSwapBuffersReq); + + swapl(&stuff->n); + + if (stuff->n != 0) { + pSwapInfo = (xDbeSwapInfo *) stuff + 1; + + /* The swap info following the fix part of this request is a window(32) + * followed by a 1 byte swap action and then 3 pad bytes. We only need + * to swap the window information. + */ + for (i = 0; i < stuff->n; i++) { + swapl(&pSwapInfo->window); + } + } + + return (ProcDbeSwapBuffers(client)); + +} /* SProcDbeSwapBuffers() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeBeginIdiom + * + * Description: + * + * This function is for processing a DbeBeginIdiom request on a swapped + * server. This request informs the server that a complex swap will + * immediately follow this request. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +SProcDbeBeginIdiom(ClientPtr client) +{ + REQUEST(xDbeBeginIdiomReq); + + swaps(&stuff->length); + return (ProcDbeBeginIdiom(client)); + +} /* SProcDbeBeginIdiom() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeGetVisualInfo + * + * Description: + * + * This function is for processing a ProcDbeGetVisualInfo request on a + * swapped server. This request returns information about which visuals + * support double buffering. + * + * Return Values: + * + * BadDrawable - value in screen specifiers is not a valid drawable + * Success + * + *****************************************************************************/ + +static int +SProcDbeGetVisualInfo(ClientPtr client) +{ + REQUEST(xDbeGetVisualInfoReq); + + swaps(&stuff->length); + REQUEST_AT_LEAST_SIZE(xDbeGetVisualInfoReq); + + swapl(&stuff->n); + SwapRestL(stuff); + + return (ProcDbeGetVisualInfo(client)); + +} /* SProcDbeGetVisualInfo() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeGetbackBufferAttributes + * + * Description: + * + * This function is for processing a ProcDbeGetbackBufferAttributes + * request on a swapped server. This request returns information about a + * back buffer. + * + * Return Values: + * + * Success + * + *****************************************************************************/ + +static int +SProcDbeGetBackBufferAttributes(ClientPtr client) +{ + REQUEST(xDbeGetBackBufferAttributesReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xDbeGetBackBufferAttributesReq); + + swapl(&stuff->buffer); + + return (ProcDbeGetBackBufferAttributes(client)); + +} /* SProcDbeGetBackBufferAttributes() */ + +/****************************************************************************** + * + * DBE DIX Procedure: SProcDbeDispatch + * + * Description: + * + * This function dispatches DBE requests on a swapped server. + * + *****************************************************************************/ + +static int +SProcDbeDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DbeGetVersion: + return (SProcDbeGetVersion(client)); + + case X_DbeAllocateBackBufferName: + return (SProcDbeAllocateBackBufferName(client)); + + case X_DbeDeallocateBackBufferName: + return (SProcDbeDeallocateBackBufferName(client)); + + case X_DbeSwapBuffers: + return (SProcDbeSwapBuffers(client)); + + case X_DbeBeginIdiom: + return (SProcDbeBeginIdiom(client)); + + case X_DbeEndIdiom: + return (Success); + + case X_DbeGetVisualInfo: + return (SProcDbeGetVisualInfo(client)); + + case X_DbeGetBackBufferAttributes: + return (SProcDbeGetBackBufferAttributes(client)); + + default: + return (BadRequest); + } + +} /* SProcDbeDispatch() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeSetupBackgroundPainter + * + * Description: + * + * This function sets up pGC to clear pixmaps. + * + * Return Values: + * + * TRUE - setup was successful + * FALSE - the window's background state is NONE + * + *****************************************************************************/ + +static Bool +DbeSetupBackgroundPainter(WindowPtr pWin, GCPtr pGC) +{ + pointer gcvalues[4]; + + int ts_x_origin, ts_y_origin; + + PixUnion background; + + int backgroundState; + + Mask gcmask; + + /* First take care of any ParentRelative stuff by altering the + * tile/stipple origin to match the coordinates of the upper-left + * corner of the first ancestor without a ParentRelative background. + * This coordinate is, of course, negative. + */ + ts_x_origin = ts_y_origin = 0; + while (pWin->backgroundState == ParentRelative) { + ts_x_origin -= pWin->origin.x; + ts_y_origin -= pWin->origin.y; + + pWin = pWin->parent; + } + backgroundState = pWin->backgroundState; + background = pWin->background; + + switch (backgroundState) { + case BackgroundPixel: + gcvalues[0] = (pointer) background.pixel; + gcvalues[1] = (pointer) FillSolid; + gcmask = GCForeground | GCFillStyle; + break; + + case BackgroundPixmap: + gcvalues[0] = (pointer) FillTiled; + gcvalues[1] = (pointer) background.pixmap; + gcvalues[2] = (pointer) (long) ts_x_origin; + gcvalues[3] = (pointer) (long) ts_y_origin; + gcmask = GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; + break; + + default: + /* pWin->backgroundState == None */ + return (FALSE); + } + + if (DoChangeGC(pGC, gcmask, (XID *) gcvalues, TRUE) != 0) { + return (FALSE); + } + + return (TRUE); + +} /* DbeSetupBackgroundPainter() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeDrawableDelete + * + * Description: + * + * This is the resource delete function for dbeDrawableResType. + * It is registered when the drawable resource type is created in + * DbeExtensionInit(). + * + * To make resource deletion simple, we do not do anything in this function + * and leave all resource deleteion to DbeWindowPrivDelete(), which will + * eventually be called or already has been called. Deletion functions are + * not guaranteed to be called in any particular order. + * + *****************************************************************************/ +static int +DbeDrawableDelete(pointer pDrawable, XID id) +{ + return Success; + +} /* DbeDrawableDelete() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeWindowPrivDelete + * + * Description: + * + * This is the resource delete function for dbeWindowPrivResType. + * It is registered when the drawable resource type is created in + * DbeExtensionInit(). + * + *****************************************************************************/ +static int +DbeWindowPrivDelete(pointer pDbeWinPriv, XID id) +{ + DbeScreenPrivPtr pDbeScreenPriv; + DbeWindowPrivPtr pDbeWindowPriv = (DbeWindowPrivPtr) pDbeWinPriv; + int i; + + /* + ************************************************************************** + ** Remove the buffer ID from the ID array. + ************************************************************************** + */ + + /* Find the ID in the ID array. */ + i = 0; + while ((i < pDbeWindowPriv->nBufferIDs) && (pDbeWindowPriv->IDs[i] != id)) { + i++; + } + + if (i == pDbeWindowPriv->nBufferIDs) { + /* We did not find the ID in the array. We should never get here. */ + return BadValue; + } + + /* Remove the ID from the array. */ + + if (i < (pDbeWindowPriv->nBufferIDs - 1)) { + /* Compress the buffer ID array, overwriting the ID in the process. */ + memmove(&pDbeWindowPriv->IDs[i], &pDbeWindowPriv->IDs[i + 1], + (pDbeWindowPriv->nBufferIDs - i - 1) * sizeof(XID)); + } + else { + /* We are removing the last ID in the array, in which case, the + * assignement below is all that we need to do. + */ + } + pDbeWindowPriv->IDs[pDbeWindowPriv->nBufferIDs - 1] = DBE_FREE_ID_ELEMENT; + + pDbeWindowPriv->nBufferIDs--; + + /* If an extended array was allocated, then check to see if the remaining + * buffer IDs will fit in the static array. + */ + + if ((pDbeWindowPriv->maxAvailableIDs > DBE_INIT_MAX_IDS) && + (pDbeWindowPriv->nBufferIDs == DBE_INIT_MAX_IDS)) { + /* Copy the IDs back into the static array. */ + memcpy(pDbeWindowPriv->initIDs, pDbeWindowPriv->IDs, + DBE_INIT_MAX_IDS * sizeof(XID)); + + /* Free the extended array; use the static array. */ + free(pDbeWindowPriv->IDs); + pDbeWindowPriv->IDs = pDbeWindowPriv->initIDs; + pDbeWindowPriv->maxAvailableIDs = DBE_INIT_MAX_IDS; + } + + /* + ************************************************************************** + ** Perform DDX level tasks. + ************************************************************************** + */ + + pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW_PRIV((DbeWindowPrivPtr) + pDbeWindowPriv); + (*pDbeScreenPriv->WinPrivDelete) ((DbeWindowPrivPtr) pDbeWindowPriv, id); + + /* + ************************************************************************** + ** Perform miscellaneous tasks if this is the last buffer associated + ** with the window. + ************************************************************************** + */ + + if (pDbeWindowPriv->nBufferIDs == 0) { + /* Reset the DBE window priv pointer. */ + pDbeWindowPriv->pWindow->devPrivates[dbeWindowPrivIndex].ptr = + (pointer) NULL; + + /* We are done with the window priv. */ + free(pDbeWindowPriv); + } + + return (Success); + +} /* DbeWindowPrivDelete() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeResetProc + * + * Description: + * + * This routine is called at the end of every server generation. + * It deallocates any memory reserved for the extension and performs any + * other tasks related to shutting down the extension. + * + *****************************************************************************/ +static void +DbeResetProc(ExtensionEntry * extEntry) +{ + int i; + + ScreenPtr pScreen; + + DbeScreenPrivPtr pDbeScreenPriv; + + if (dbeScreenPrivIndex < 0) { + return; + } + + for (i = 0; i < screenInfo.numScreens; i++) { + pScreen = screenInfo.screens[i]; + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + if (pDbeScreenPriv) { + /* Unwrap DestroyWindow, which was wrapped in DbeExtensionInit(). */ + pScreen->DestroyWindow = pDbeScreenPriv->DestroyWindow; + + if (pDbeScreenPriv->ResetProc) + (*pDbeScreenPriv->ResetProc) (pScreen); + + if (pDbeScreenPriv->winPrivPrivSizes) { + free(pDbeScreenPriv->winPrivPrivSizes); + } + + free(pDbeScreenPriv); + } + } + + /* We want to init the initialization function table after every server + * reset in DbeRegisterFunction(). + */ + firstRegistrationPass = TRUE; + +} /* DbeResetProc() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeDestroyWindow + * + * Description: + * + * This is the wrapper for pScreen->DestroyWindow. + * This function frees buffer resources for a window before it is + * destroyed. + * + *****************************************************************************/ + +static Bool +DbeDestroyWindow(WindowPtr pWin) +{ + DbeScreenPrivPtr pDbeScreenPriv; + DbeWindowPrivPtr pDbeWindowPriv; + ScreenPtr pScreen; + Bool ret; + + /* + ************************************************************************** + ** 1. Unwrap the member routine. + ************************************************************************** + */ + + pScreen = pWin->drawable.pScreen; + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + pScreen->DestroyWindow = pDbeScreenPriv->DestroyWindow; + + /* + ************************************************************************** + ** 2. Do any work necessary before the member routine is called. + ** + ** Call the window priv delete function for all buffer IDs associated + ** with this window. + ************************************************************************** + */ + + if ((pDbeWindowPriv = DBE_WINDOW_PRIV(pWin))) { + while (pDbeWindowPriv) { + /* *DbeWinPrivDelete() will free the window private and set it to + * NULL if there are no more buffer IDs associated with this + * window. + */ + FreeResource(pDbeWindowPriv->IDs[0], RT_NONE); + pDbeWindowPriv = DBE_WINDOW_PRIV(pWin); + } + } + + /* + ************************************************************************** + ** 3. Call the member routine, saving its result if necessary. + ************************************************************************** + */ + + ret = (*pScreen->DestroyWindow) (pWin); + + /* + ************************************************************************** + ** 4. Rewrap the member routine, restoring the wrapper value first in case + ** the wrapper (or something that it wrapped) change this value. + ************************************************************************** + */ + + pDbeScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DbeDestroyWindow; + + /* + ************************************************************************** + ** 5. Do any work necessary after the member routine has been called. + ** + ** In this case we do not need to do anything. + ************************************************************************** + */ + + return ret; + +} /* DbeDestroyWindow() */ + +/****************************************************************************** + * + * DBE DIX Procedure: DbeExtensionInit + * + * Description: + * + * Called from InitExtensions in main() + * + *****************************************************************************/ + +void +DbeExtensionInit(void) +{ + ExtensionEntry *extEntry; + + int i, j; + + ScreenPtr pScreen = NULL; + + DbeScreenPrivPtr pDbeScreenPriv; + + int nStubbedScreens = 0; + + Bool ddxInitSuccess; + + + /* Allocate private pointers in windows and screens. */ + + if ((dbeScreenPrivIndex = AllocateScreenPrivateIndex()) < 0) { + return; + } + + if ((dbeWindowPrivIndex = AllocateWindowPrivateIndex()) < 0) { + return; + } + + /* Initialize the priv priv counts between server generations. */ + winPrivPrivCount = 0; + + /* Create the resource types. */ + dbeDrawableResType = + CreateNewResourceType(DbeDrawableDelete) | RC_CACHED | RC_DRAWABLE; + dbeWindowPrivResType = CreateNewResourceType(DbeWindowPrivDelete); + + for (i = 0; i < screenInfo.numScreens; i++) { + /* For each screen, set up DBE screen privates and init DIX and DDX + * interface. + */ + + pScreen = screenInfo.screens[i]; + + if (!AllocateWindowPrivate(pScreen, dbeWindowPrivIndex, 0) || + !(pDbeScreenPriv = + calloc(sizeof(DbeScreenPrivRec), 1))) { + /* If we can not alloc a window or screen private, + * then free any privates that we already alloc'ed and return + */ + + for (j = 0; j < i; j++) { + free(screenInfo.screens[j]->devPrivates[dbeScreenPrivIndex]. + ptr); + screenInfo.screens[j]->devPrivates[dbeScreenPrivIndex].ptr = + NULL; + } + return; + } + + pScreen->devPrivates[dbeScreenPrivIndex].ptr = (pointer) pDbeScreenPriv; + + /* Store the DBE priv priv size info for later use when allocating + * priv privs at the driver level. + */ + pDbeScreenPriv->winPrivPrivLen = 0; + pDbeScreenPriv->winPrivPrivSizes = (unsigned *) NULL; + pDbeScreenPriv->totalWinPrivSize = sizeof(DbeWindowPrivRec); + + /* Copy the resource types */ + pDbeScreenPriv->dbeDrawableResType = dbeDrawableResType; + pDbeScreenPriv->dbeWindowPrivResType = dbeWindowPrivResType; + + /* Copy the private indices */ + pDbeScreenPriv->dbeScreenPrivIndex = dbeScreenPrivIndex; + pDbeScreenPriv->dbeWindowPrivIndex = dbeWindowPrivIndex; + + if (DbeInitFunct[i]) { + /* This screen supports DBE. */ + + /* Setup DIX. */ + pDbeScreenPriv->SetupBackgroundPainter = DbeSetupBackgroundPainter; + pDbeScreenPriv->AllocWinPriv = DbeAllocWinPriv; + pDbeScreenPriv->AllocWinPrivPrivIndex = DbeAllocWinPrivPrivIndex; + pDbeScreenPriv->AllocWinPrivPriv = DbeAllocWinPrivPriv; + + /* Setup DDX. */ + ddxInitSuccess = (*DbeInitFunct[i]) (pScreen, pDbeScreenPriv); + + /* DDX DBE initialization may have the side affect of + * reallocating pDbeScreenPriv, so we need to update it. + */ + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + if (ddxInitSuccess) { + /* Wrap DestroyWindow. The DDX initialization function + * already wrapped PositionWindow for us. + */ + + pDbeScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DbeDestroyWindow; + } + else { + /* DDX initialization failed. Stub the screen. */ + DbeStubScreen(pDbeScreenPriv, &nStubbedScreens); + } + } + else { + /* This screen does not support DBE. */ + +#ifndef DISABLE_MI_DBE_BY_DEFAULT + /* Setup DIX. */ + pDbeScreenPriv->SetupBackgroundPainter = DbeSetupBackgroundPainter; + pDbeScreenPriv->AllocWinPriv = DbeAllocWinPriv; + pDbeScreenPriv->AllocWinPrivPrivIndex = DbeAllocWinPrivPrivIndex; + pDbeScreenPriv->AllocWinPrivPriv = DbeAllocWinPrivPriv; + + /* Setup DDX. */ + ddxInitSuccess = miDbeInit(pScreen, pDbeScreenPriv); + + /* DDX DBE initialization may have the side affect of + * reallocating pDbeScreenPriv, so we need to update it. + */ + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + if (ddxInitSuccess) { + /* Wrap DestroyWindow. The DDX initialization function + * already wrapped PositionWindow for us. + */ + + pDbeScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = DbeDestroyWindow; + } + else { + /* DDX initialization failed. Stub the screen. */ + DbeStubScreen(pDbeScreenPriv, &nStubbedScreens); + } +#else + DbeStubScreen(pDbeScreenPriv, &nStubbedScreens); +#endif + + } + + } /* for (i = 0; i < screenInfo.numScreens; i++) */ + + if (nStubbedScreens == screenInfo.numScreens) { + /* All screens stubbed. Clean up and return. */ + + for (i = 0; i < screenInfo.numScreens; i++) { + free(screenInfo.screens[i]->devPrivates[dbeScreenPrivIndex].ptr); + pScreen->devPrivates[dbeScreenPrivIndex].ptr = NULL; + } + return; + } + + /* Now add the extension. */ + extEntry = AddExtension(DBE_PROTOCOL_NAME, DbeNumberEvents, + DbeNumberErrors, ProcDbeDispatch, SProcDbeDispatch, + DbeResetProc, StandardMinorOpcode); + + dbeErrorBase = extEntry->errorBase; + +} /* DbeExtensionInit() */ diff --git a/dbe/dbestruct.h b/dbe/dbestruct.h new file mode 100644 index 0000000..c102a6f --- /dev/null +++ b/dbe/dbestruct.h @@ -0,0 +1,226 @@ +/****************************************************************************** + * + * Copyright (c) 1994, 1995 Hewlett-Packard Company + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the Hewlett-Packard + * Company shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the Hewlett-Packard Company. + * + * Header file for DIX-related DBE + * + *****************************************************************************/ + +#ifndef DBE_STRUCT_H +#define DBE_STRUCT_H + +/* INCLUDES */ + +#define NEED_DBE_PROTOCOL +#include +#include "windowstr.h" + +typedef struct { + VisualID visual; /* one visual ID that supports double-buffering */ + int depth; /* depth of visual in bits */ + int perflevel; /* performance level of visual */ +} XdbeVisualInfo; + +typedef struct { + int count; /* number of items in visual_depth */ + XdbeVisualInfo *visinfo; /* list of visuals & depths for scrn */ +} XdbeScreenVisualInfo; + +/* DEFINES */ + +#define DBE_SCREEN_PRIV(pScreen) \ + ((dbeScreenPrivIndex < 0) ? \ + NULL : \ + ((DbeScreenPrivPtr)((pScreen)->devPrivates[dbeScreenPrivIndex].ptr))) + +#define DBE_SCREEN_PRIV_FROM_DRAWABLE(pDrawable) \ + DBE_SCREEN_PRIV((pDrawable)->pScreen) + +#define DBE_SCREEN_PRIV_FROM_WINDOW_PRIV(pDbeWindowPriv) \ + DBE_SCREEN_PRIV((pDbeWindowPriv)->pWindow->drawable.pScreen) + +#define DBE_SCREEN_PRIV_FROM_WINDOW(pWindow) \ + DBE_SCREEN_PRIV((pWindow)->drawable.pScreen) + +#define DBE_SCREEN_PRIV_FROM_PIXMAP(pPixmap) \ + DBE_SCREEN_PRIV((pPixmap)->drawable.pScreen) + +#define DBE_SCREEN_PRIV_FROM_GC(pGC)\ + DBE_SCREEN_PRIV((pGC)->pScreen) + +#define DBE_WINDOW_PRIV(pWindow)\ + ((dbeWindowPrivIndex < 0) ? \ + NULL : \ + ((DbeWindowPrivPtr)(pWindow->devPrivates[dbeWindowPrivIndex].ptr))) + +/* Initial size of the buffer ID array in the window priv. */ +#define DBE_INIT_MAX_IDS 2 + +/* Reallocation increment for the buffer ID array. */ +#define DBE_INCR_MAX_IDS 4 + +/* Marker for free elements in the buffer ID array. */ +#define DBE_FREE_ID_ELEMENT 0 + +/* TYPEDEFS */ + +/* Record used to pass swap information between DIX and DDX swapping + * procedures. + */ +typedef struct _DbeSwapInfoRec { + WindowPtr pWindow; + unsigned char swapAction; + +} DbeSwapInfoRec, *DbeSwapInfoPtr; + +/* + ****************************************************************************** + ** Per-window data + ****************************************************************************** + */ + +typedef struct _DbeWindowPrivRec { + /* A pointer to the window with which the DBE window private (buffer) is + * associated. + */ + WindowPtr pWindow; + + /* Last known swap action for this buffer. Legal values for this field + * are XdbeUndefined, XdbeBackground, XdbeUntouched, and XdbeCopied. + */ + unsigned char swapAction; + + /* Last known buffer size. + */ + unsigned short width, height; + + /* Coordinates used for static gravity when the window is positioned. + */ + short x, y; + + /* Number of XIDs associated with this buffer. + */ + int nBufferIDs; + + /* Capacity of the current buffer ID array, IDs. */ + int maxAvailableIDs; + + /* Pointer to the array of buffer IDs. This initially points to initIDs. + * When the static limit of the initIDs array is reached, the array is + * reallocated and this pointer is set to the new array instead of initIDs. + */ + XID *IDs; + + /* Initial array of buffer IDs. We are defining the XID array within the + * window priv to optimize for data locality. In most cases, only one + * buffer will be associated with a window. Having the array declared + * here can prevent us from accessing the data in another memory page, + * possibly resulting in a page swap and loss of performance. Initially we + * will use this array to store buffer IDs. For situations where we have + * more IDs than can fit in this static array, we will allocate a larger + * array to use, possibly suffering a performance loss. + */ + XID initIDs[DBE_INIT_MAX_IDS]; + + /* Device-specific private information. + */ + DevUnion *devPrivates; + +} DbeWindowPrivRec, *DbeWindowPrivPtr; + +/* + ****************************************************************************** + ** Per-screen data + ****************************************************************************** + */ + +typedef struct _DbeScreenPrivRec { + /* Info for creating window privs */ + int winPrivPrivLen; /* Length of privs in DbeWindowPrivRec */ + unsigned int *winPrivPrivSizes; /* Array of private record sizes */ + unsigned int totalWinPrivSize; /* PrivRec + size of all priv priv ptrs */ + + /* Resources created by DIX to be used by DDX */ + RESTYPE dbeDrawableResType; + RESTYPE dbeWindowPrivResType; + + /* Private indices created by DIX to be used by DDX */ + int dbeScreenPrivIndex; + int dbeWindowPrivIndex; + + /* Wrapped functions + * It is the responsibilty of the DDX layer to wrap PositionWindow(). + * DbeExtensionInit wraps DestroyWindow(). + */ + PositionWindowProcPtr PositionWindow; + DestroyWindowProcPtr DestroyWindow; + + /* Per-screen DIX routines */ + Bool (*SetupBackgroundPainter) (WindowPtr /*pWin */ , + GCPtr /*pGC */ + ); + DbeWindowPrivPtr(*AllocWinPriv) (ScreenPtr /*pScreen */ + ); + int (*AllocWinPrivPrivIndex) (void); + Bool (*AllocWinPrivPriv) (ScreenPtr /*pScreen */ , + int /*index */ , + unsigned /*amount */ + ); + + /* Per-screen DDX routines */ + Bool (*GetVisualInfo) (ScreenPtr /*pScreen */ , + XdbeScreenVisualInfo * /*pVisInfo */ + ); + int (*AllocBackBufferName) (WindowPtr /*pWin */ , + XID /*bufId */ , + int /*swapAction */ + ); + int (*SwapBuffers) (ClientPtr /*client */ , + int * /*pNumWindows */ , + DbeSwapInfoPtr /*swapInfo */ + ); + void (*BeginIdiom) (ClientPtr /*client */ + ); + void (*EndIdiom) (ClientPtr /*client */ + ); + void (*WinPrivDelete) (DbeWindowPrivPtr /*pDbeWindowPriv */ , + XID /*bufId */ + ); + void (*ResetProc) (ScreenPtr /*pScreen */ + ); + void (*ValidateBuffer) (WindowPtr /*pWin */ , + XID /*bufId */ , + Bool /*dstbuffer */ + ); + + /* Device-specific private information. + */ + DevUnion *devPrivates; + +} DbeScreenPrivRec, *DbeScreenPrivPtr; + +#endif /* DBE_STRUCT_H */ diff --git a/dbe/midbe.c b/dbe/midbe.c new file mode 100644 index 0000000..a513149 --- /dev/null +++ b/dbe/midbe.c @@ -0,0 +1,791 @@ +/****************************************************************************** + * + * Copyright (c) 1994, 1995 Hewlett-Packard Company + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the Hewlett-Packard + * Company shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the Hewlett-Packard Company. + * + * Machine-independent DBE code + * + *****************************************************************************/ + +/* INCLUDES */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "resource.h" +#include "opaque.h" +#include "dbestruct.h" +#include "midbestr.h" +#include "regionstr.h" +#include "gcstruct.h" +#include "inputstr.h" +#include "midbe.h" + +#include + +/* DEFINES */ + +/* TYPEDEFS */ + +/* GLOBALS */ + +static int miDbePrivPrivGeneration = 0; + +static int miDbeWindowPrivPrivIndex = -1; + +RESTYPE dbeDrawableResType; + +RESTYPE dbeWindowPrivResType; + +int dbeScreenPrivIndex = -1; + +int dbeWindowPrivIndex = -1; + +/****************************************************************************** + * + * DBE MI Procedure: miDbeGetVisualInfo + * + * Description: + * + * This is the MI function for the DbeGetVisualInfo request. This function + * is called through pDbeScreenPriv->GetVisualInfo. This function is also + * called for the DbeAllocateBackBufferName request at the extension level; + * it is called by ProcDbeAllocateBackBufferName() in dbe.c. + * + * If memory allocation fails or we can not get the visual info, this + * function returns FALSE. Otherwise, it returns TRUE for success. + * + *****************************************************************************/ + +static Bool +miDbeGetVisualInfo(ScreenPtr pScreen, XdbeScreenVisualInfo * pScrVisInfo) +{ + int i, j, k; + int count; + DepthPtr pDepth; + XdbeVisualInfo *visInfo; + + /* Determine number of visuals for this screen. */ + for (i = 0, count = 0; i < pScreen->numDepths; i++) { + count += pScreen->allowedDepths[i].numVids; + } + + if (!count) + return FALSE; + + /* Allocate an array of XdbeVisualInfo items. */ + if (!(visInfo = malloc(count * sizeof(XdbeVisualInfo)))) { + return FALSE; /* memory alloc failure */ + } + + for (i = 0, k = 0; i < pScreen->numDepths; i++) { + /* For each depth of this screen, get visual information. */ + + pDepth = &pScreen->allowedDepths[i]; + + for (j = 0; j < pDepth->numVids; j++) { + /* For each visual for this depth of this screen, get visual ID + * and visual depth. Since this is MI code, we will always return + * the same performance level for all visuals (0). A higher + * performance level value indicates higher performance. + */ + visInfo[k].visual = pDepth->vids[j]; + visInfo[k].depth = pDepth->depth; + visInfo[k].perflevel = 0; + k++; + } + } + + /* Record the number of visuals and point visual_depth to + * the array of visual info. + */ + pScrVisInfo->count = count; + pScrVisInfo->visinfo = visInfo; + + return TRUE; /* success */ + +} /* miDbeGetVisualInfo() */ + +/****************************************************************************** + * + * DBE MI Procedure: miAllocBackBufferName + * + * Description: + * + * This is the MI function for the DbeAllocateBackBufferName request. + * + *****************************************************************************/ + +static int +miDbeAllocBackBufferName(WindowPtr pWin, XID bufId, int swapAction) +{ + ScreenPtr pScreen; + + DbeWindowPrivPtr pDbeWindowPriv; + + MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; + + DbeScreenPrivPtr pDbeScreenPriv; + + GCPtr pGC; + + xRectangle clearRect; + + pScreen = pWin->drawable.pScreen; + pDbeWindowPriv = DBE_WINDOW_PRIV(pWin); + + if (pDbeWindowPriv->nBufferIDs == 0) { + /* There is no buffer associated with the window. + * We have to create the window priv priv. Remember, the window + * priv was created at the DIX level, so all we need to do is + * create the priv priv and attach it to the priv. + */ + + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + /* Setup the window priv priv. */ + pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); + pDbeWindowPrivPriv->pDbeWindowPriv = pDbeWindowPriv; + + /* Get a front pixmap. */ + if (!(pDbeWindowPrivPriv->pFrontBuffer = + (*pScreen->CreatePixmap) (pScreen, pDbeWindowPriv->width, + pDbeWindowPriv->height, + pWin->drawable.depth))) { + return (BadAlloc); + } + + /* Get a back pixmap. */ + if (!(pDbeWindowPrivPriv->pBackBuffer = + (*pScreen->CreatePixmap) (pScreen, pDbeWindowPriv->width, + pDbeWindowPriv->height, + pWin->drawable.depth))) { + (*pScreen->DestroyPixmap) (pDbeWindowPrivPriv->pFrontBuffer); + return (BadAlloc); + } + + /* Make the back pixmap a DBE drawable resource. */ + if (!AddResource(bufId, dbeDrawableResType, + (pointer) pDbeWindowPrivPriv->pBackBuffer)) { + /* free the buffer and the drawable resource */ + FreeResource(bufId, RT_NONE); + return (BadAlloc); + } + + /* Attach the priv priv to the priv. */ + pDbeWindowPriv->devPrivates[miDbeWindowPrivPrivIndex].ptr = + (pointer) pDbeWindowPrivPriv; + + /* Clear the back buffer. */ + pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); + if ((*pDbeScreenPriv->SetupBackgroundPainter) (pWin, pGC)) { + ValidateGC((DrawablePtr) pDbeWindowPrivPriv->pBackBuffer, pGC); + clearRect.x = clearRect.y = 0; + clearRect.width = pDbeWindowPrivPriv->pBackBuffer->drawable.width; + clearRect.height = pDbeWindowPrivPriv->pBackBuffer->drawable.height; + (*pGC->ops->PolyFillRect) ((DrawablePtr) pDbeWindowPrivPriv-> + pBackBuffer, pGC, 1, &clearRect); + } + FreeScratchGC(pGC); + + } /* if no buffer associated with the window */ + + else { + /* A buffer is already associated with the window. + * Place the new buffer ID information at the head of the ID list. + */ + + /* Associate the new ID with an existing pixmap. */ + pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); + if (!AddResource(bufId, dbeDrawableResType, + (pointer) pDbeWindowPrivPriv->pBackBuffer)) { + return (BadAlloc); + } + + } + + return (Success); + +} /* miDbeAllocBackBufferName() */ + +/****************************************************************************** + * + * DBE MI Procedure: miDbeAliasBuffers + * + * Description: + * + * This function associates all XIDs of a buffer with the back pixmap + * stored in the window priv. + * + *****************************************************************************/ + +static void +miDbeAliasBuffers(DbeWindowPrivPtr pDbeWindowPriv) +{ + int i; + + MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv = + MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); + + for (i = 0; i < pDbeWindowPriv->nBufferIDs; i++) { + ChangeResourceValue(pDbeWindowPriv->IDs[i], dbeDrawableResType, + (pointer) pDbeWindowPrivPriv->pBackBuffer); + } + +} /* miDbeAliasBuffers() */ + +/****************************************************************************** + * + * DBE MI Procedure: miDbeSwapBuffers + * + * Description: + * + * This is the MI function for the DbeSwapBuffers request. + * + *****************************************************************************/ + +static int +miDbeSwapBuffers(ClientPtr client, int *pNumWindows, DbeSwapInfoPtr swapInfo) +{ + DbeScreenPrivPtr pDbeScreenPriv; + + GCPtr pGC; + + WindowPtr pWin; + + MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; + + PixmapPtr pTmpBuffer; + + xRectangle clearRect; + + pWin = swapInfo[0].pWindow; + pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(pWin); + pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV_FROM_WINDOW(pWin); + pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); + + /* + ********************************************************************** + ** Setup before swap. + ********************************************************************** + */ + + switch (swapInfo[0].swapAction) { + case XdbeUndefined: + break; + + case XdbeBackground: + break; + + case XdbeUntouched: + ValidateGC((DrawablePtr) pDbeWindowPrivPriv->pFrontBuffer, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pWin, + (DrawablePtr) pDbeWindowPrivPriv->pFrontBuffer, + pGC, 0, 0, pWin->drawable.width, + pWin->drawable.height, 0, 0); + break; + + case XdbeCopied: + break; + + } + + /* + ********************************************************************** + ** Swap. + ********************************************************************** + */ + + ValidateGC((DrawablePtr) pWin, pGC); + (*pGC->ops->CopyArea) ((DrawablePtr) pDbeWindowPrivPriv->pBackBuffer, + (DrawablePtr) pWin, pGC, 0, 0, + pWin->drawable.width, pWin->drawable.height, 0, 0); + + /* + ********************************************************************** + ** Tasks after swap. + ********************************************************************** + */ + + switch (swapInfo[0].swapAction) { + case XdbeUndefined: + break; + + case XdbeBackground: + if ((*pDbeScreenPriv->SetupBackgroundPainter) (pWin, pGC)) { + ValidateGC((DrawablePtr) pDbeWindowPrivPriv->pBackBuffer, pGC); + clearRect.x = 0; + clearRect.y = 0; + clearRect.width = pDbeWindowPrivPriv->pBackBuffer->drawable.width; + clearRect.height = pDbeWindowPrivPriv->pBackBuffer->drawable.height; + (*pGC->ops->PolyFillRect) ((DrawablePtr) pDbeWindowPrivPriv-> + pBackBuffer, pGC, 1, &clearRect); + } + break; + + case XdbeUntouched: + /* Swap pixmap pointers. */ + pTmpBuffer = pDbeWindowPrivPriv->pBackBuffer; + pDbeWindowPrivPriv->pBackBuffer = pDbeWindowPrivPriv->pFrontBuffer; + pDbeWindowPrivPriv->pFrontBuffer = pTmpBuffer; + + miDbeAliasBuffers(pDbeWindowPrivPriv->pDbeWindowPriv); + + break; + + case XdbeCopied: + break; + + } + + /* Remove the swapped window from the swap information array and decrement + * pNumWindows to indicate to the DIX level how many windows were actually + * swapped. + */ + + if (*pNumWindows > 1) { + /* We were told to swap more than one window, but we only swapped the + * first one. Remove the first window in the list by moving the last + * window to the beginning. + */ + swapInfo[0].pWindow = swapInfo[*pNumWindows - 1].pWindow; + swapInfo[0].swapAction = swapInfo[*pNumWindows - 1].swapAction; + + /* Clear the last window information just to be safe. */ + swapInfo[*pNumWindows - 1].pWindow = (WindowPtr) NULL; + swapInfo[*pNumWindows - 1].swapAction = 0; + } + else { + /* Clear the window information just to be safe. */ + swapInfo[0].pWindow = (WindowPtr) NULL; + swapInfo[0].swapAction = 0; + } + + (*pNumWindows)--; + + FreeScratchGC(pGC); + + return Success; + +} /* miSwapBuffers() */ + +/****************************************************************************** + * + * DBE MI Procedure: miDbeWinPrivDelete + * + * Description: + * + * This is the MI function for deleting the dbeWindowPrivResType resource. + * This function is invoked indirectly by calling FreeResource() to free + * the resources associated with a DBE buffer ID. There are 5 ways that + * miDbeWinPrivDelete() can be called by FreeResource(). They are: + * + * - A DBE window is destroyed, in which case the DbeDestroyWindow() + * wrapper is invoked. The wrapper calls FreeResource() for all DBE + * buffer IDs. + * + * - miDbeAllocBackBufferName() calls FreeResource() to clean up resources + * after a buffer allocation failure. + * + * - The PositionWindow wrapper, miDbePositionWindow(), calls + * FreeResource() when it fails to create buffers of the new size. + * FreeResource() is called for all DBE buffer IDs. + * + * - FreeClientResources() calls FreeResource() when a client dies or the + * the server resets. + * + * When FreeResource() is called for a DBE buffer ID, the delete function + * for the only other type of DBE resource, dbeDrawableResType, is also + * invoked. This delete function (DbeDrawableDelete) is a NOOP to make + * resource deletion easier. It is not guaranteed which delete function is + * called first. Hence, we will let miDbeWinPrivDelete() free all DBE + * resources. + * + * This function deletes/frees the following stuff associated with + * the window private: + * + * - the ID node in the ID list representing the passed in ID. + * + * In addition, pDbeWindowPriv->nBufferIDs is decremented. + * + * If this function is called for the last/only buffer ID for a window, + * these are additionally deleted/freed: + * + * - the front and back pixmaps + * - the window priv itself + * + *****************************************************************************/ + +static void +miDbeWinPrivDelete(DbeWindowPrivPtr pDbeWindowPriv, XID bufId) +{ + MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; + + if (pDbeWindowPriv->nBufferIDs != 0) { + /* We still have at least one more buffer ID associated with this + * window. + */ + return; + } + + /* We have no more buffer IDs associated with this window. We need to + * free some stuff. + */ + + pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); + + /* Destroy the front and back pixmaps. */ + if (pDbeWindowPrivPriv->pFrontBuffer) { + (*pDbeWindowPriv->pWindow->drawable.pScreen-> + DestroyPixmap) (pDbeWindowPrivPriv->pFrontBuffer); + } + if (pDbeWindowPrivPriv->pBackBuffer) { + (*pDbeWindowPriv->pWindow->drawable.pScreen-> + DestroyPixmap) (pDbeWindowPrivPriv->pBackBuffer); + } + +} /* miDbeWinPrivDelete() */ + +/****************************************************************************** + * + * DBE MI Procedure: miDbePositionWindow + * + * Description: + * + * This function was cloned from miMbxPositionWindow() in mimultibuf.c. + * This function resizes the buffer when the window is resized. + * + *****************************************************************************/ + +static Bool +miDbePositionWindow(WindowPtr pWin, int x, int y) +{ + ScreenPtr pScreen; + DbeScreenPrivPtr pDbeScreenPriv; + DbeWindowPrivPtr pDbeWindowPriv; + int width, height; + int dx, dy, dw, dh; + int sourcex, sourcey; + int destx, desty; + int savewidth, saveheight; + PixmapPtr pFrontBuffer; + PixmapPtr pBackBuffer; + Bool clear; + GCPtr pGC; + xRectangle clearRect; + Bool ret; + + /* + ************************************************************************** + ** 1. Unwrap the member routine. + ************************************************************************** + */ + + pScreen = pWin->drawable.pScreen; + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + pScreen->PositionWindow = pDbeScreenPriv->PositionWindow; + + /* + ************************************************************************** + ** 2. Do any work necessary before the member routine is called. + ** + ** In this case we do not need to do anything. + ************************************************************************** + */ + + /* + ************************************************************************** + ** 3. Call the member routine, saving its result if necessary. + ************************************************************************** + */ + + ret = (*pScreen->PositionWindow) (pWin, x, y); + + /* + ************************************************************************** + ** 4. Rewrap the member routine, restoring the wrapper value first in case + ** the wrapper (or something that it wrapped) change this value. + ************************************************************************** + */ + + pDbeScreenPriv->PositionWindow = pScreen->PositionWindow; + pScreen->PositionWindow = miDbePositionWindow; + + /* + ************************************************************************** + ** 5. Do any work necessary after the member routine has been called. + ************************************************************************** + */ + + if (!(pDbeWindowPriv = DBE_WINDOW_PRIV(pWin))) { + return ret; + } + + if (pDbeWindowPriv->width == pWin->drawable.width && + pDbeWindowPriv->height == pWin->drawable.height) { + return ret; + } + + width = pWin->drawable.width; + height = pWin->drawable.height; + + dx = pWin->drawable.x - pDbeWindowPriv->x; + dy = pWin->drawable.y - pDbeWindowPriv->y; + dw = width - pDbeWindowPriv->width; + dh = height - pDbeWindowPriv->height; + + GravityTranslate(0, 0, -dx, -dy, dw, dh, pWin->bitGravity, &destx, &desty); + + clear = ((pDbeWindowPriv->width < (unsigned short) width) || + (pDbeWindowPriv->height < (unsigned short) height) || + (pWin->bitGravity == ForgetGravity)); + + sourcex = 0; + sourcey = 0; + savewidth = pDbeWindowPriv->width; + saveheight = pDbeWindowPriv->height; + + /* Clip rectangle to source and destination. */ + if (destx < 0) { + savewidth += destx; + sourcex -= destx; + destx = 0; + } + + if (destx + savewidth > width) { + savewidth = width - destx; + } + + if (desty < 0) { + saveheight += desty; + sourcey -= desty; + desty = 0; + } + + if (desty + saveheight > height) { + saveheight = height - desty; + } + + pDbeWindowPriv->width = width; + pDbeWindowPriv->height = height; + pDbeWindowPriv->x = pWin->drawable.x; + pDbeWindowPriv->y = pWin->drawable.y; + + pGC = GetScratchGC(pWin->drawable.depth, pScreen); + + if (clear) { + if ((*pDbeScreenPriv->SetupBackgroundPainter) (pWin, pGC)) { + clearRect.x = 0; + clearRect.y = 0; + clearRect.width = width; + clearRect.height = height; + } + else { + clear = FALSE; + } + } + + /* Create DBE buffer pixmaps equal to size of resized window. */ + pFrontBuffer = (*pScreen->CreatePixmap) (pScreen, width, height, + pWin->drawable.depth); + + pBackBuffer = (*pScreen->CreatePixmap) (pScreen, width, height, + pWin->drawable.depth); + + if (!pFrontBuffer || !pBackBuffer) { + /* We failed at creating 1 or 2 of the pixmaps. */ + + if (pFrontBuffer) { + (*pScreen->DestroyPixmap) (pFrontBuffer); + } + + if (pBackBuffer) { + (*pScreen->DestroyPixmap) (pBackBuffer); + } + + /* Destroy all buffers for this window. */ + while (pDbeWindowPriv) { + /* DbeWindowPrivDelete() will free the window private if there no + * more buffer IDs associated with this window. + */ + FreeResource(pDbeWindowPriv->IDs[0], RT_NONE); + pDbeWindowPriv = DBE_WINDOW_PRIV(pWin); + } + + FreeScratchGC(pGC); + return (FALSE); + } + + else { + /* Clear out the new DBE buffer pixmaps. */ + + MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; + + pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); + ValidateGC((DrawablePtr) pFrontBuffer, pGC); + + /* I suppose this could avoid quite a bit of work if + * it computed the minimal area required. + */ + if (clear) { + (*pGC->ops->PolyFillRect) ((DrawablePtr) pFrontBuffer, pGC, 1, + &clearRect); + (*pGC->ops->PolyFillRect) ((DrawablePtr) pBackBuffer, pGC, 1, + &clearRect); + } + + /* Copy the contents of the old DBE pixmaps to the new pixmaps. */ + if (pWin->bitGravity != ForgetGravity) { + (*pGC->ops->CopyArea) ((DrawablePtr) pDbeWindowPrivPriv-> + pFrontBuffer, (DrawablePtr) pFrontBuffer, + pGC, sourcex, sourcey, savewidth, saveheight, + destx, desty); + (*pGC->ops->CopyArea) ((DrawablePtr) pDbeWindowPrivPriv-> + pBackBuffer, (DrawablePtr) pBackBuffer, pGC, + sourcex, sourcey, savewidth, saveheight, + destx, desty); + } + + /* Destroy the old pixmaps, and point the DBE window priv to the new + * pixmaps. + */ + + (*pScreen->DestroyPixmap) (pDbeWindowPrivPriv->pFrontBuffer); + (*pScreen->DestroyPixmap) (pDbeWindowPrivPriv->pBackBuffer); + + pDbeWindowPrivPriv->pFrontBuffer = pFrontBuffer; + pDbeWindowPrivPriv->pBackBuffer = pBackBuffer; + + /* Make sure all XID are associated with the new back pixmap. */ + miDbeAliasBuffers(pDbeWindowPriv); + + FreeScratchGC(pGC); + } + + return (ret); + +} /* miDbePositionWindow() */ + +/****************************************************************************** + * + * DBE MI Procedure: miDbeResetProc + * + * Description: + * + * This function is called from DbeResetProc(), which is called at the end + * of every server generation. This function peforms any MI-specific + * shutdown tasks. + * + *****************************************************************************/ + +static void +miDbeResetProc(ScreenPtr pScreen) +{ + DbeScreenPrivPtr pDbeScreenPriv; + + pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); + + /* Unwrap wrappers */ + pScreen->PositionWindow = pDbeScreenPriv->PositionWindow; + +} /* miDbeResetProc() */ + +static void +miDbeNopValidateBuffer(WindowPtr pWin, XID bufId, Bool dstbuffer) +{ +} + +/****************************************************************************** + * + * DBE MI Procedure: miDbeInit + * + * Description: + * + * This is the MI initialization function called by DbeExtensionInit(). + * + *****************************************************************************/ + +Bool +miDbeInit(ScreenPtr pScreen, DbeScreenPrivPtr pDbeScreenPriv) +{ + /* Copy resource types created by DIX */ + dbeDrawableResType = pDbeScreenPriv->dbeDrawableResType; + dbeWindowPrivResType = pDbeScreenPriv->dbeWindowPrivResType; + + /* Copy private indices created by DIX */ + dbeScreenPrivIndex = pDbeScreenPriv->dbeScreenPrivIndex; + dbeWindowPrivIndex = pDbeScreenPriv->dbeWindowPrivIndex; + + /* Reset the window priv privs if generations do not match. */ + if (miDbePrivPrivGeneration != serverGeneration) { + /* + ********************************************************************** + ** Allocate the window priv priv. + ********************************************************************** + */ + + miDbeWindowPrivPrivIndex = (*pDbeScreenPriv->AllocWinPrivPrivIndex) (); + + /* Make sure we only do this code once. */ + miDbePrivPrivGeneration = serverGeneration; + + } /* if -- Reset priv privs. */ + + if (!(*pDbeScreenPriv->AllocWinPrivPriv) (pScreen, + miDbeWindowPrivPrivIndex, + sizeof(MiDbeWindowPrivPrivRec))) { + return (FALSE); + } + + /* Wrap functions. */ + pDbeScreenPriv->PositionWindow = pScreen->PositionWindow; + pScreen->PositionWindow = miDbePositionWindow; + + /* Initialize the per-screen DBE function pointers. */ + pDbeScreenPriv->GetVisualInfo = miDbeGetVisualInfo; + pDbeScreenPriv->AllocBackBufferName = miDbeAllocBackBufferName; + pDbeScreenPriv->SwapBuffers = miDbeSwapBuffers; + pDbeScreenPriv->BeginIdiom = 0; + pDbeScreenPriv->EndIdiom = 0; + pDbeScreenPriv->ResetProc = miDbeResetProc; + pDbeScreenPriv->WinPrivDelete = miDbeWinPrivDelete; + + /* The mi implementation doesn't need buffer validation. */ + pDbeScreenPriv->ValidateBuffer = miDbeNopValidateBuffer; + + return (TRUE); + +} /* miDbeInit() */ diff --git a/dbe/midbe.h b/dbe/midbe.h new file mode 100644 index 0000000..051528f --- /dev/null +++ b/dbe/midbe.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 1994, 1995 Hewlett-Packard Company + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the Hewlett-Packard + * Company shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the Hewlett-Packard Company. + * + * Header file for users of machine-independent DBE code + * + *****************************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef MIDBE_H +#define MIDBE_H + +/* EXTERNS */ + +extern Bool miDbeInit(ScreenPtr pScreen, DbeScreenPrivPtr pDbeScreenPriv); + +#endif /* MIDBE_H */ diff --git a/dbe/midbestr.h b/dbe/midbestr.h new file mode 100644 index 0000000..2447444 --- /dev/null +++ b/dbe/midbestr.h @@ -0,0 +1,93 @@ +/****************************************************************************** + * + * Copyright (c) 1994, 1995 Hewlett-Packard Company + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the Hewlett-Packard + * Company shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the Hewlett-Packard Company. + * + * Header file for users of machine-independent DBE code + * + *****************************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef MIDBE_STRUCT_H +#define MIDBE_STRUCT_H + +/* DEFINES */ + +#define MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv) \ + (((miDbeWindowPrivPrivIndex < 0) || (!pDbeWindowPriv)) ? \ + NULL : \ + ((MiDbeWindowPrivPrivPtr) \ + ((pDbeWindowPriv)->devPrivates[miDbeWindowPrivPrivIndex].ptr))) + +#define MI_DBE_WINDOW_PRIV_PRIV_FROM_WINDOW(pWin)\ + MI_DBE_WINDOW_PRIV_PRIV(DBE_WINDOW_PRIV(pWin)) + +#define MI_DBE_SCREEN_PRIV_PRIV(pDbeScreenPriv) \ + (((miDbeScreenPrivPrivIndex < 0) || (!pDbeScreenPriv)) ? \ + NULL : \ + ((MiDbeScreenPrivPrivPtr) \ + ((pDbeScreenPriv)->devPrivates[miDbeScreenPrivPrivIndex].ptr))) + +/* TYPEDEFS */ + +typedef struct _MiDbeWindowPrivPrivRec { + /* Place machine-specific fields in here. + * Since this is mi code, we do not really have machine-specific fields. + */ + + /* Pointer to a drawable that contains the contents of the back buffer. + */ + PixmapPtr pBackBuffer; + + /* Pointer to a drawable that contains the contents of the front buffer. + * This pointer is only used for the XdbeUntouched swap action. For that + * swap action, we need to copy the front buffer (window) contents into + * this drawable, copy the contents of current back buffer drawable (the + * back buffer) into the window, swap the front and back drawable pointers, + * and then swap the drawable/resource associations in the resource + * database. + */ + PixmapPtr pFrontBuffer; + + /* Pointer back to our window private with which we are associated. */ + DbeWindowPrivPtr pDbeWindowPriv; + +} MiDbeWindowPrivPrivRec, *MiDbeWindowPrivPrivPtr; + +typedef struct _MiDbeScreenPrivPrivRec { + /* Place machine-specific fields in here. + * Since this is mi code, we do not really have machine-specific fields. + */ + + /* Pointer back to our screen private with which we are associated. */ + DbeScreenPrivPtr pDbeScreenPriv; + +} MiDbeScreenPrivPrivRec, *MiDbeScreenPrivPrivPtr; + +#endif /* MIDBE_STRUCT_H */ diff --git a/dix/Makefile.am b/dix/Makefile.am new file mode 100644 index 0000000..9f64c95 --- /dev/null +++ b/dix/Makefile.am @@ -0,0 +1,33 @@ +noinst_LTLIBRARIES = libdix.la + +AM_CFLAGS = $(DIX_CFLAGS) \ + -DVENDOR_STRING=\""@VENDOR_STRING@"\" \ + -DVENDOR_RELEASE="@VENDOR_RELEASE@" + +libdix_la_SOURCES = \ + atom.c \ + colormap.c \ + cursor.c \ + devices.c \ + dispatch.c \ + dispatch.h \ + dixfonts.c \ + dixutils.c \ + events.c \ + extension.c \ + ffs.c \ + gc.c \ + globals.c \ + glyphcurs.c \ + grabs.c \ + initatoms.c \ + main.c \ + pixmap.c \ + privates.c \ + property.c \ + resource.c \ + swaprep.c \ + swapreq.c \ + tables.c \ + window.c \ + strcasecmp.c diff --git a/dix/atom.c b/dix/atom.c new file mode 100644 index 0000000..bd44ea8 --- /dev/null +++ b/dix/atom.c @@ -0,0 +1,212 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "misc.h" +#include "resource.h" +#include "dix.h" + +#define InitialTableSize 100 + +typedef struct _Node { + struct _Node *left, *right; + Atom a; + unsigned int fingerPrint; + char *string; +} NodeRec, *NodePtr; + +static Atom lastAtom = None; + +static NodePtr atomRoot = (NodePtr) NULL; + +static unsigned long tableLength; + +static NodePtr *nodeTable; + +void FreeAtom(NodePtr patom); + +_X_EXPORT Atom +MakeAtom(char *string, unsigned len, Bool makeit) +{ + NodePtr *np; + + unsigned i; + + int comp; + + unsigned int fp = 0; + + np = &atomRoot; + for (i = 0; i < (len + 1) / 2; i++) { + fp = fp * 27 + string[i]; + fp = fp * 27 + string[len - 1 - i]; + } + while (*np != (NodePtr) NULL) { + if (fp < (*np)->fingerPrint) + np = &((*np)->left); + else if (fp > (*np)->fingerPrint) + np = &((*np)->right); + else { /* now start testing the strings */ + comp = strncmp(string, (*np)->string, (int) len); + if ((comp < 0) || ((comp == 0) && (len < strlen((*np)->string)))) + np = &((*np)->left); + else if (comp > 0) + np = &((*np)->right); + else + return (*np)->a; + } + } + if (makeit) { + NodePtr nd; + + nd = malloc(sizeof(NodeRec)); + if (!nd) + return BAD_RESOURCE; + if (lastAtom < XA_LAST_PREDEFINED) { + nd->string = string; + } + else { + nd->string = malloc(len + 1); + if (!nd->string) { + free(nd); + return BAD_RESOURCE; + } + strncpy(nd->string, string, (int) len); + nd->string[len] = 0; + } + if ((lastAtom + 1) >= tableLength) { + NodePtr *table; + + table = (NodePtr *) realloc(nodeTable, + tableLength * (2 * sizeof(NodePtr))); + if (!table) { + if (nd->string != string) + free(nd->string); + free(nd); + return BAD_RESOURCE; + } + tableLength <<= 1; + nodeTable = table; + } + *np = nd; + nd->left = nd->right = (NodePtr) NULL; + nd->fingerPrint = fp; + nd->a = (++lastAtom); + *(nodeTable + lastAtom) = nd; + return nd->a; + } + else + return None; +} + +_X_EXPORT Bool +ValidAtom(Atom atom) +{ + return (atom != None) && (atom <= lastAtom); +} + +_X_EXPORT char * +NameForAtom(Atom atom) +{ + NodePtr node; + + if (atom > lastAtom) + return 0; + if ((node = nodeTable[atom]) == (NodePtr) NULL) + return 0; + return node->string; +} + +void +AtomError() +{ + FatalError("initializing atoms"); +} + +void +FreeAtom(NodePtr patom) +{ + if (patom->left) + FreeAtom(patom->left); + if (patom->right) + FreeAtom(patom->right); + if (patom->a > XA_LAST_PREDEFINED) + free(patom->string); + free(patom); +} + +void +FreeAllAtoms() +{ + if (atomRoot == (NodePtr) NULL) + return; + FreeAtom(atomRoot); + atomRoot = (NodePtr) NULL; + free(nodeTable); + nodeTable = (NodePtr *) NULL; + lastAtom = None; +} + +void +InitAtoms() +{ + FreeAllAtoms(); + tableLength = InitialTableSize; + nodeTable = malloc(InitialTableSize * sizeof(NodePtr)); + if (!nodeTable) + AtomError(); + nodeTable[None] = (NodePtr) NULL; + MakePredeclaredAtoms(); + if (lastAtom != XA_LAST_PREDEFINED) + AtomError(); +} diff --git a/dix/colormap.c b/dix/colormap.c new file mode 100644 index 0000000..83b4ad1 --- /dev/null +++ b/dix/colormap.c @@ -0,0 +1,2555 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "misc.h" +#include "dix.h" +#include "colormapst.h" +#include "os.h" +#include "scrnintstr.h" +#include "resource.h" +#include "windowstr.h" + +extern XID clientErrorValue; + +extern int colormapPrivateCount; + +static Pixel FindBestPixel(EntryPtr /*pentFirst */ , + int /*size */ , + xrgb * /*prgb */ , + int /*channel */ + ); + +static int AllComp(EntryPtr /*pent */ , + xrgb * /*prgb */ + ); + +static int RedComp(EntryPtr /*pent */ , + xrgb * /*prgb */ + ); + +static int GreenComp(EntryPtr /*pent */ , + xrgb * /*prgb */ + ); + +static int BlueComp(EntryPtr /*pent */ , + xrgb * /*prgb */ + ); + +static void FreePixels(register ColormapPtr /*pmap */ , + register int /*client */ + ); + +static void CopyFree(int /*channel */ , + int /*client */ , + ColormapPtr /*pmapSrc */ , + ColormapPtr /*pmapDst */ + ); + +static void FreeCell(ColormapPtr /*pmap */ , + Pixel /*i */ , + int /*channel */ + ); + +static void UpdateColors(ColormapPtr /*pmap */ + ); + +static int AllocDirect(int /*client */ , + ColormapPtr /*pmap */ , + int /*c */ , + int /*r */ , + int /*g */ , + int /*b */ , + Bool /*contig */ , + Pixel * /*pixels */ , + Pixel * /*prmask */ , + Pixel * /*pgmask */ , + Pixel * /*pbmask */ + ); + +static int AllocPseudo(int /*client */ , + ColormapPtr /*pmap */ , + int /*c */ , + int /*r */ , + Bool /*contig */ , + Pixel * /*pixels */ , + Pixel * /*pmask */ , + Pixel ** /*pppixFirst */ + ); + +static Bool AllocCP(ColormapPtr /*pmap */ , + EntryPtr /*pentFirst */ , + int /*count */ , + int /*planes */ , + Bool /*contig */ , + Pixel * /*pixels */ , + Pixel * /*pMask */ + ); + +static Bool AllocShared(ColormapPtr /*pmap */ , + Pixel * /*ppix */ , + int /*c */ , + int /*r */ , + int /*g */ , + int /*b */ , + Pixel /*rmask */ , + Pixel /*gmask */ , + Pixel /*bmask */ , + Pixel * /*ppixFirst */ + ); + +static int FreeCo(ColormapPtr /*pmap */ , + int /*client */ , + int /*color */ , + int /*npixIn */ , + Pixel * /*ppixIn */ , + Pixel /*mask */ + ); + +static int TellNoMap(WindowPtr /*pwin */ , + Colormap * /*pmid */ + ); + +static void FindColorInRootCmap(ColormapPtr /* pmap */ , + EntryPtr /* pentFirst */ , + int /* size */ , + xrgb * /* prgb */ , + Pixel * /* pPixel */ , + int /* channel */ , + ColorCompareProcPtr /* comp */ + ); + +#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1) +#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1) +#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1) +#define ALPHAMASK(vis) 0 + +#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis)) + +/* GetNextBitsOrBreak(bits, mask, base) -- + * (Suggestion: First read the macro, then read this explanation. + * + * Either generate the next value to OR in to a pixel or break out of this + * while loop + * + * This macro is used when we're trying to generate all 2^n combinations of + * bits in mask. What we're doing here is counting in binary, except that + * the bits we use to count may not be contiguous. This macro will be + * called 2^n times, returning a different value in bits each time. Then + * it will cause us to break out of a surrounding loop. (It will always be + * called from within a while loop.) + * On call: mask is the value we want to find all the combinations for + * base has 1 bit set where the least significant bit of mask is set + * + * For example,if mask is 01010, base should be 0010 and we count like this: + * 00010 (see this isn't so hard), + * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so + * we add that to bits getting (0100 + 0100) = + * 01000 for our next value. + * then we add 0010 to get + * 01010 and we're done (easy as 1, 2, 3) + */ +#define GetNextBitsOrBreak(bits, mask, base) \ + if((bits) == (mask)) \ + break; \ + (bits) += (base); \ + while((bits) & ~(mask)) \ + (bits) += ((bits) & ~(mask)); +/* ID of server as client */ +#define SERVER_ID 0 + +typedef struct _colorResource { + Colormap mid; + int client; +} colorResource; + +/* Invariants: + * refcnt == 0 means entry is empty + * refcnt > 0 means entry is useable by many clients, so it can't be changed + * refcnt == AllocPrivate means entry owned by one client only + * fShared should only be set if refcnt == AllocPrivate, and only in red map + */ + +/** + * Create and initialize the color map + * + * \param mid resource to use for this colormap + * \param alloc 1 iff all entries are allocated writable + */ +_X_EXPORT int +CreateColormap(Colormap mid, ScreenPtr pScreen, VisualPtr pVisual, + ColormapPtr *ppcmap, int alloc, int client) +{ + int class, size; + + unsigned long sizebytes; + + ColormapPtr pmap; + + EntryPtr pent; + + int i; + + Pixel *ppix, **pptr; + + class = pVisual->class; + if (!(class & DynamicClass) && (alloc != AllocNone) && + (client != SERVER_ID)) + return (BadMatch); + + size = pVisual->ColormapEntries; + sizebytes = (size * sizeof(Entry)) + + (MAXCLIENTS * sizeof(Pixel *)) + (MAXCLIENTS * sizeof(int)); + if ((class | DynamicClass) == DirectColor) + sizebytes *= 3; + sizebytes += sizeof(ColormapRec); + pmap = malloc(sizebytes); + if (!pmap) + return (BadAlloc); +#if defined(_XSERVER64) + pmap->pad0 = 0; + pmap->pad1 = 0; +#if (X_BYTE_ORDER == X_LITTLE_ENDIAN) + pmap->pad2 = 0; +#endif +#endif + pmap->red = (EntryPtr) ((char *) pmap + sizeof(ColormapRec)); + sizebytes = size * sizeof(Entry); + pmap->clientPixelsRed = (Pixel **) ((char *) pmap->red + sizebytes); + pmap->numPixelsRed = (int *) ((char *) pmap->clientPixelsRed + + (MAXCLIENTS * sizeof(Pixel *))); + pmap->mid = mid; + pmap->flags = 0; /* start out with all flags clear */ + if (mid == pScreen->defColormap) + pmap->flags |= IsDefault; + pmap->pScreen = pScreen; + pmap->pVisual = pVisual; + pmap->class = class; + if ((class | DynamicClass) == DirectColor) + size = NUMRED(pVisual); + pmap->freeRed = size; + bzero((char *) pmap->red, (int) sizebytes); + bzero((char *) pmap->numPixelsRed, MAXCLIENTS * sizeof(int)); + for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; + --pptr >= pmap->clientPixelsRed;) + *pptr = (Pixel *) NULL; + if (alloc == AllocAll) { + if (class & DynamicClass) + pmap->flags |= AllAllocated; + for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--) + pent->refcnt = AllocPrivate; + pmap->freeRed = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) { + free(pmap); + return (BadAlloc); + } + pmap->clientPixelsRed[client] = ppix; + for (i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsRed[client] = size; + } + + if ((class | DynamicClass) == DirectColor) { + pmap->freeGreen = NUMGREEN(pVisual); + pmap->green = (EntryPtr) ((char *) pmap->numPixelsRed + + (MAXCLIENTS * sizeof(int))); + pmap->clientPixelsGreen = (Pixel **) ((char *) pmap->green + sizebytes); + pmap->numPixelsGreen = (int *) ((char *) pmap->clientPixelsGreen + + (MAXCLIENTS * sizeof(Pixel *))); + pmap->freeBlue = NUMBLUE(pVisual); + pmap->blue = (EntryPtr) ((char *) pmap->numPixelsGreen + + (MAXCLIENTS * sizeof(int))); + pmap->clientPixelsBlue = (Pixel **) ((char *) pmap->blue + sizebytes); + pmap->numPixelsBlue = (int *) ((char *) pmap->clientPixelsBlue + + (MAXCLIENTS * sizeof(Pixel *))); + + bzero((char *) pmap->green, (int) sizebytes); + bzero((char *) pmap->blue, (int) sizebytes); + + memmove((char *) pmap->clientPixelsGreen, + (char *) pmap->clientPixelsRed, MAXCLIENTS * sizeof(Pixel *)); + memmove((char *) pmap->clientPixelsBlue, + (char *) pmap->clientPixelsRed, MAXCLIENTS * sizeof(Pixel *)); + bzero((char *) pmap->numPixelsGreen, MAXCLIENTS * sizeof(int)); + bzero((char *) pmap->numPixelsBlue, MAXCLIENTS * sizeof(int)); + + /* If every cell is allocated, mark its refcnt */ + if (alloc == AllocAll) { + size = pmap->freeGreen; + for (pent = &pmap->green[size - 1]; pent >= pmap->green; pent--) + pent->refcnt = AllocPrivate; + pmap->freeGreen = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) { + free(pmap->clientPixelsRed[client]); + free(pmap); + return (BadAlloc); + } + pmap->clientPixelsGreen[client] = ppix; + for (i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsGreen[client] = size; + + size = pmap->freeBlue; + for (pent = &pmap->blue[size - 1]; pent >= pmap->blue; pent--) + pent->refcnt = AllocPrivate; + pmap->freeBlue = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) { + free(pmap->clientPixelsGreen[client]); + free(pmap->clientPixelsRed[client]); + free(pmap); + return (BadAlloc); + } + pmap->clientPixelsBlue[client] = ppix; + for (i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsBlue[client] = size; + } + } + if (!AddResource(mid, RT_COLORMAP, (pointer) pmap)) + return (BadAlloc); + /* If the device wants a chance to initialize the colormap in any way, + * this is it. In specific, if this is a Static colormap, this is the + * time to fill in the colormap's values */ + pmap->flags |= BeingCreated; + + /* + * Allocate the array of devPrivate's for this colormap. + */ + + if (colormapPrivateCount == 0) + pmap->devPrivates = NULL; + else { + pmap->devPrivates = + calloc(sizeof(DevUnion), colormapPrivateCount); + if (!pmap->devPrivates) { + FreeResource(mid, RT_NONE); + return BadAlloc; + } + } + + if (!(*pScreen->CreateColormap) (pmap)) { + FreeResource(mid, RT_NONE); + return BadAlloc; + } + pmap->flags &= ~BeingCreated; + *ppcmap = pmap; + return (Success); +} + +/** + * + * \param value must conform to DeleteType + */ +int +FreeColormap(pointer value, XID mid) +{ + int i; + + EntryPtr pent; + + ColormapPtr pmap = (ColormapPtr) value; + + if (CLIENT_ID(mid) != SERVER_ID) { + (*pmap->pScreen->UninstallColormap) (pmap); + WalkTree(pmap->pScreen, (VisitWindowProcPtr) TellNoMap, (pointer) &mid); + } + + /* This is the device's chance to undo anything it needs to, especially + * to free any storage it allocated */ + (*pmap->pScreen->DestroyColormap) (pmap); + + if (pmap->clientPixelsRed) { + for (i = 0; i < MAXCLIENTS; i++) + free(pmap->clientPixelsRed[i]); + } + + if ((pmap->class == PseudoColor) || (pmap->class == GrayScale)) { + for (pent = &pmap->red[pmap->pVisual->ColormapEntries - 1]; + pent >= pmap->red; pent--) { + if (pent->fShared) { + if (--pent->co.shco.red->refcnt == 0) + free(pent->co.shco.red); + if (--pent->co.shco.green->refcnt == 0) + free(pent->co.shco.green); + if (--pent->co.shco.blue->refcnt == 0) + free(pent->co.shco.blue); + } + } + } + if ((pmap->class | DynamicClass) == DirectColor) { + for (i = 0; i < MAXCLIENTS; i++) { + free(pmap->clientPixelsGreen[i]); + free(pmap->clientPixelsBlue[i]); + } + } + + if (pmap->devPrivates) + free(pmap->devPrivates); + + free(pmap); + return (Success); +} + +/* Tell window that pmid has disappeared */ +static int +TellNoMap(WindowPtr pwin, Colormap * pmid) +{ + xEvent xE; + + if (wColormap(pwin) == *pmid) { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = None; + xE.u.colormap.new = TRUE; + xE.u.colormap.state = ColormapUninstalled; + DeliverEvents(pwin, &xE, 1, (WindowPtr) NULL); + if (pwin->optional) { + pwin->optional->colormap = None; + CheckWindowOptionalNeed(pwin); + } + } + + return (WT_WALKCHILDREN); +} + +/* Tell window that pmid got uninstalled */ +_X_EXPORT int +TellLostMap(WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *) value; + + xEvent xE; + + if (wColormap(pwin) == *pmid) { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = *pmid; + xE.u.colormap.new = FALSE; + xE.u.colormap.state = ColormapUninstalled; + DeliverEvents(pwin, &xE, 1, (WindowPtr) NULL); + } + + return (WT_WALKCHILDREN); +} + +/* Tell window that pmid got installed */ +_X_EXPORT int +TellGainedMap(WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *) value; + + xEvent xE; + + if (wColormap(pwin) == *pmid) { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = *pmid; + xE.u.colormap.new = FALSE; + xE.u.colormap.state = ColormapInstalled; + DeliverEvents(pwin, &xE, 1, (WindowPtr) NULL); + } + + return (WT_WALKCHILDREN); +} + +int +CopyColormapAndFree(Colormap mid, ColormapPtr pSrc, int client) +{ + ColormapPtr pmap = (ColormapPtr) NULL; + + int result, alloc, size; + + Colormap midSrc; + + ScreenPtr pScreen; + + VisualPtr pVisual; + + pScreen = pSrc->pScreen; + pVisual = pSrc->pVisual; + midSrc = pSrc->mid; + alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ? + AllocAll : AllocNone; + size = pVisual->ColormapEntries; + + /* If the create returns non-0, it failed */ + result = CreateColormap(mid, pScreen, pVisual, &pmap, alloc, client); + if (result != Success) + return (result); + if (alloc == AllocAll) { + memmove((char *) pmap->red, (char *) pSrc->red, size * sizeof(Entry)); + if ((pmap->class | DynamicClass) == DirectColor) { + memmove((char *) pmap->green, (char *) pSrc->green, + size * sizeof(Entry)); + memmove((char *) pmap->blue, (char *) pSrc->blue, + size * sizeof(Entry)); + } + pSrc->flags &= ~AllAllocated; + FreePixels(pSrc, client); + UpdateColors(pmap); + return (Success); + } + + CopyFree(REDMAP, client, pSrc, pmap); + if ((pmap->class | DynamicClass) == DirectColor) { + CopyFree(GREENMAP, client, pSrc, pmap); + CopyFree(BLUEMAP, client, pSrc, pmap); + } + if (pmap->class & DynamicClass) + UpdateColors(pmap); + /* XXX should worry about removing any RT_CMAPENTRY resource */ + return (Success); +} + +/* Helper routine for freeing large numbers of cells from a map */ +static void +CopyFree(int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst) +{ + int z, npix; + + EntryPtr pentSrcFirst, pentDstFirst; + + EntryPtr pentSrc, pentDst; + + Pixel *ppix; + + int nalloc; + + switch (channel) { + default: /* so compiler can see that everything gets initialized */ + case REDMAP: + ppix = (pmapSrc->clientPixelsRed)[client]; + npix = (pmapSrc->numPixelsRed)[client]; + pentSrcFirst = pmapSrc->red; + pentDstFirst = pmapDst->red; + break; + case GREENMAP: + ppix = (pmapSrc->clientPixelsGreen)[client]; + npix = (pmapSrc->numPixelsGreen)[client]; + pentSrcFirst = pmapSrc->green; + pentDstFirst = pmapDst->green; + break; + case BLUEMAP: + ppix = (pmapSrc->clientPixelsBlue)[client]; + npix = (pmapSrc->numPixelsBlue)[client]; + pentSrcFirst = pmapSrc->blue; + pentDstFirst = pmapDst->blue; + break; + } + nalloc = 0; + if (pmapSrc->class & DynamicClass) { + for (z = npix; --z >= 0; ppix++) { + /* Copy entries */ + pentSrc = pentSrcFirst + *ppix; + pentDst = pentDstFirst + *ppix; + if (pentDst->refcnt > 0) { + pentDst->refcnt++; + } + else { + *pentDst = *pentSrc; + nalloc++; + if (pentSrc->refcnt > 0) + pentDst->refcnt = 1; + else + pentSrc->fShared = FALSE; + } + FreeCell(pmapSrc, *ppix, channel); + } + } + + /* Note that FreeCell has already fixed pmapSrc->free{Color} */ + switch (channel) { + case REDMAP: + pmapDst->freeRed -= nalloc; + (pmapDst->clientPixelsRed)[client] = (pmapSrc->clientPixelsRed)[client]; + (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL; + (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client]; + (pmapSrc->numPixelsRed)[client] = 0; + break; + case GREENMAP: + pmapDst->freeGreen -= nalloc; + (pmapDst->clientPixelsGreen)[client] = + (pmapSrc->clientPixelsGreen)[client]; + (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL; + (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client]; + (pmapSrc->numPixelsGreen)[client] = 0; + break; + case BLUEMAP: + pmapDst->freeBlue -= nalloc; + pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client]; + pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL; + pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client]; + pmapSrc->numPixelsBlue[client] = 0; + break; + } +} + +/* Free the ith entry in a color map. Must handle freeing of + * colors allocated through AllocColorPlanes */ +static void +FreeCell(ColormapPtr pmap, Pixel i, int channel) +{ + EntryPtr pent; + + int *pCount; + + switch (channel) { + default: /* so compiler can see that everything gets initialized */ + case PSEUDOMAP: + case REDMAP: + pent = (EntryPtr) & pmap->red[i]; + pCount = &pmap->freeRed; + break; + case GREENMAP: + pent = (EntryPtr) & pmap->green[i]; + pCount = &pmap->freeGreen; + break; + case BLUEMAP: + pent = (EntryPtr) & pmap->blue[i]; + pCount = &pmap->freeBlue; + break; + } + /* If it's not privately allocated and it's not time to free it, just + * decrement the count */ + if (pent->refcnt > 1) + pent->refcnt--; + else { + /* If the color type is shared, find the sharedcolor. If decremented + * refcnt is 0, free the shared cell. */ + if (pent->fShared) { + if (--pent->co.shco.red->refcnt == 0) + free(pent->co.shco.red); + if (--pent->co.shco.green->refcnt == 0) + free(pent->co.shco.green); + if (--pent->co.shco.blue->refcnt == 0) + free(pent->co.shco.blue); + pent->fShared = FALSE; + } + pent->refcnt = 0; + *pCount += 1; + } +} + +static void +UpdateColors(ColormapPtr pmap) +{ + xColorItem *defs; + + xColorItem *pdef; + + EntryPtr pent; + + VisualPtr pVisual; + + int i, n, size; + + pVisual = pmap->pVisual; + size = pVisual->ColormapEntries; + defs = (xColorItem *) ALLOCATE_LOCAL(size * sizeof(xColorItem)); + if (!defs) + return; + n = 0; + pdef = defs; + if (pmap->class == DirectColor) { + for (i = 0; i < size; i++) { + if (!pmap->red[i].refcnt && + !pmap->green[i].refcnt && !pmap->blue[i].refcnt) + continue; + pdef->pixel = ((Pixel) i << pVisual->offsetRed) | + ((Pixel) i << pVisual->offsetGreen) | + ((Pixel) i << pVisual->offsetBlue); + pdef->red = pmap->red[i].co.local.red; + pdef->green = pmap->green[i].co.local.green; + pdef->blue = pmap->blue[i].co.local.blue; + pdef->flags = DoRed | DoGreen | DoBlue; + pdef++; + n++; + } + } + else { + for (i = 0, pent = pmap->red; i < size; i++, pent++) { + if (!pent->refcnt) + continue; + pdef->pixel = i; + if (pent->fShared) { + pdef->red = pent->co.shco.red->color; + pdef->green = pent->co.shco.green->color; + pdef->blue = pent->co.shco.blue->color; + } + else { + pdef->red = pent->co.local.red; + pdef->green = pent->co.local.green; + pdef->blue = pent->co.local.blue; + } + pdef->flags = DoRed | DoGreen | DoBlue; + pdef++; + n++; + } + } + if (n) + (*pmap->pScreen->StoreColors) (pmap, n, defs); + DEALLOCATE_LOCAL(defs); +} + +/* Get a read-only color from a ColorMap (probably slow for large maps) + * Returns by changing the value in pred, pgreen, pblue and pPix + */ +_X_EXPORT int +AllocColor(ColormapPtr pmap, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue, + Pixel * pPix, int client) +{ + Pixel pixR, pixG, pixB; + + int entries; + + xrgb rgb; + + int class; + + VisualPtr pVisual; + + int npix; + + Pixel *ppix; + + pVisual = pmap->pVisual; + (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual); + rgb.red = *pred; + rgb.green = *pgreen; + rgb.blue = *pblue; + class = pmap->class; + entries = pVisual->ColormapEntries; + + /* If the colormap is being created, then we want to be able to change + * the colormap, even if it's a static type. Otherwise, we'd never be + * able to initialize static colormaps + */ + if (pmap->flags & BeingCreated) + class |= DynamicClass; + + /* If this is one of the static storage classes, and we're not initializing + * it, the best we can do is to find the closest color entry to the + * requested one and return that. + */ + switch (class) { + case StaticColor: + case StaticGray: + /* Look up all three components in the same pmap */ + *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); + *pred = pmap->red[pixR].co.local.red; + *pgreen = pmap->red[pixR].co.local.green; + *pblue = pmap->red[pixR].co.local.blue; + npix = pmap->numPixelsRed[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return (BadAlloc); + ppix[npix] = pixR; + pmap->clientPixelsRed[client] = ppix; + pmap->numPixelsRed[client]++; + break; + + case TrueColor: + /* Look up each component in its own map, then OR them together */ + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); + *pPix = (pixR << pVisual->offsetRed) | + (pixG << pVisual->offsetGreen) | + (pixB << pVisual->offsetBlue) | ALPHAMASK(pVisual); + + *pred = pmap->red[pixR].co.local.red; + *pgreen = pmap->green[pixG].co.local.green; + *pblue = pmap->blue[pixB].co.local.blue; + npix = pmap->numPixelsRed[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return (BadAlloc); + ppix[npix] = pixR; + pmap->clientPixelsRed[client] = ppix; + npix = pmap->numPixelsGreen[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return (BadAlloc); + ppix[npix] = pixG; + pmap->clientPixelsGreen[client] = ppix; + npix = pmap->numPixelsBlue[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return (BadAlloc); + ppix[npix] = pixB; + pmap->clientPixelsBlue[client] = ppix; + pmap->numPixelsRed[client]++; + pmap->numPixelsGreen[client]++; + pmap->numPixelsBlue[client]++; + break; + + case GrayScale: + case PseudoColor: + if (pmap->mid != pmap->pScreen->defColormap && + pmap->pVisual->vid == pmap->pScreen->rootVisual) { + ColormapPtr prootmap = (ColormapPtr) + SecurityLookupIDByType(clients[client], + pmap->pScreen->defColormap, + RT_COLORMAP, SecurityReadAccess); + + if (pmap->class == prootmap->class) + FindColorInRootCmap(prootmap, prootmap->red, entries, &rgb, + pPix, PSEUDOMAP, AllComp); + } + if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP, + client, AllComp) != Success) + return (BadAlloc); + break; + + case DirectColor: + if (pmap->mid != pmap->pScreen->defColormap && + pmap->pVisual->vid == pmap->pScreen->rootVisual) { + ColormapPtr prootmap = (ColormapPtr) + SecurityLookupIDByType(clients[client], + pmap->pScreen->defColormap, + RT_COLORMAP, SecurityReadAccess); + + if (pmap->class == prootmap->class) { + pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; + FindColorInRootCmap(prootmap, prootmap->red, entries, &rgb, + &pixR, REDMAP, RedComp); + pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; + FindColorInRootCmap(prootmap, prootmap->green, entries, &rgb, + &pixG, GREENMAP, GreenComp); + pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; + FindColorInRootCmap(prootmap, prootmap->blue, entries, &rgb, + &pixB, BLUEMAP, BlueComp); + *pPix = pixR | pixG | pixB; + } + } + + pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; + if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, + client, RedComp) != Success) + return (BadAlloc); + pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; + if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, + GREENMAP, client, GreenComp) != Success) { + (void) FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel) 0); + return (BadAlloc); + } + pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; + if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, + client, BlueComp) != Success) { + (void) FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel) 0); + (void) FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel) 0); + return (BadAlloc); + } + *pPix = pixR | pixG | pixB | ALPHAMASK(pVisual); + + break; + } + + /* if this is the client's first pixel in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((pmap->numPixelsRed[client] == 1) && + (CLIENT_ID(pmap->mid) != client) && !(pmap->flags & BeingCreated)) { + colorResource *pcr; + + pcr = malloc(sizeof(colorResource)); + if (!pcr) { + (void) FreeColors(pmap, client, 1, pPix, (Pixel) 0); + return (BadAlloc); + } + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer) pcr)) + return (BadAlloc); + } + return (Success); +} + +/* + * FakeAllocColor -- fake an AllocColor request by + * returning a free pixel if availible, otherwise returning + * the closest matching pixel. This is used by the mi + * software sprite code to recolor cursors. A nice side-effect + * is that this routine will never return failure. + */ + +_X_EXPORT void +FakeAllocColor(register ColormapPtr pmap, register xColorItem * item) +{ + Pixel pixR, pixG, pixB; + + Pixel temp; + + int entries; + + xrgb rgb; + + int class; + + VisualPtr pVisual; + + pVisual = pmap->pVisual; + rgb.red = item->red; + rgb.green = item->green; + rgb.blue = item->blue; + (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual); + class = pmap->class; + entries = pVisual->ColormapEntries; + + switch (class) { + case GrayScale: + case PseudoColor: + item->pixel = 0; + if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP, + -1, AllComp) == Success) { + item->pixel = temp; + break; + } + /* fall through ... */ + case StaticColor: + case StaticGray: + item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); + break; + + case DirectColor: + /* Look up each component in its own map, then OR them together */ + pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed; + pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen; + pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, + -1, RedComp) != Success) + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP) + << pVisual->offsetRed; + if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, + GREENMAP, -1, GreenComp) != Success) + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, + GREENMAP) << pVisual->offsetGreen; + if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, + -1, BlueComp) != Success) + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP) + << pVisual->offsetBlue; + item->pixel = pixR | pixG | pixB; + break; + + case TrueColor: + /* Look up each component in its own map, then OR them together */ + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); + item->pixel = (pixR << pVisual->offsetRed) | + (pixG << pVisual->offsetGreen) | (pixB << pVisual->offsetBlue); + break; + } +} + +/* free a pixel value obtained from FakeAllocColor */ +_X_EXPORT void +FakeFreeColor(register ColormapPtr pmap, Pixel pixel) +{ + VisualPtr pVisual; + + Pixel pixR, pixG, pixB; + + switch (pmap->class) { + case GrayScale: + case PseudoColor: + if (pmap->red[pixel].refcnt == AllocTemporary) + pmap->red[pixel].refcnt = 0; + break; + case DirectColor: + pVisual = pmap->pVisual; + pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed; + pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; + pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (pmap->red[pixR].refcnt == AllocTemporary) + pmap->red[pixR].refcnt = 0; + if (pmap->green[pixG].refcnt == AllocTemporary) + pmap->green[pixG].refcnt = 0; + if (pmap->blue[pixB].refcnt == AllocTemporary) + pmap->blue[pixB].refcnt = 0; + break; + } +} + +typedef unsigned short BigNumUpper; + +typedef unsigned long BigNumLower; + +#define BIGNUMLOWERBITS 24 +#define BIGNUMUPPERBITS 16 +#define BIGNUMLOWER (1 << BIGNUMLOWERBITS) +#define BIGNUMUPPER (1 << BIGNUMUPPERBITS) +#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS) +#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1)) + +typedef struct _bignum { + BigNumUpper upper; + BigNumLower lower; +} BigNumRec, *BigNumPtr; + +#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\ + ((x)->upper == (y)->upper && (x)->lower > (y)->lower)) + +#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \ + ((r)->lower = LOWERPART(u))) + +#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \ + ((r)->lower = BIGNUMLOWER-1)) + +static void +BigNumAdd(BigNumPtr x, BigNumPtr y, BigNumPtr r) +{ + BigNumLower lower, carry = 0; + + lower = x->lower + y->lower; + if (lower >= BIGNUMLOWER) { + lower -= BIGNUMLOWER; + carry = 1; + } + r->lower = lower; + r->upper = x->upper + y->upper + carry; +} + +static Pixel +FindBestPixel(EntryPtr pentFirst, int size, xrgb * prgb, int channel) +{ + EntryPtr pent; + + Pixel pixel, final; + + long dr, dg, db; + + unsigned long sq; + + BigNumRec minval, sum, temp; + + final = 0; + MaxBigNum(&minval); + /* look for the minimal difference */ + for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++) { + dr = dg = db = 0; + switch (channel) { + case PSEUDOMAP: + dg = (long) pent->co.local.green - prgb->green; + db = (long) pent->co.local.blue - prgb->blue; + case REDMAP: + dr = (long) pent->co.local.red - prgb->red; + break; + case GREENMAP: + dg = (long) pent->co.local.green - prgb->green; + break; + case BLUEMAP: + db = (long) pent->co.local.blue - prgb->blue; + break; + } + sq = dr * dr; + UnsignedToBigNum(sq, &sum); + sq = dg * dg; + UnsignedToBigNum(sq, &temp); + BigNumAdd(&sum, &temp, &sum); + sq = db * db; + UnsignedToBigNum(sq, &temp); + BigNumAdd(&sum, &temp, &sum); + if (BigNumGreater(&minval, &sum)) { + final = pixel; + minval = sum; + } + } + return (final); +} + +static void +FindColorInRootCmap(ColormapPtr pmap, EntryPtr pentFirst, int size, + xrgb * prgb, Pixel * pPixel, int channel, + ColorCompareProcPtr comp) +{ + EntryPtr pent; + + Pixel pixel; + + int count; + + if ((pixel = *pPixel) >= size) + pixel = 0; + for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++) { + if (pent->refcnt > 0 && (*comp) (pent, prgb)) { + switch (channel) { + case REDMAP: + pixel <<= pmap->pVisual->offsetRed; + break; + case GREENMAP: + pixel <<= pmap->pVisual->offsetGreen; + break; + case BLUEMAP: + pixel <<= pmap->pVisual->offsetBlue; + break; + default: /* PSEUDOMAP */ + break; + } + *pPixel = pixel; + } + } +} + +/* Tries to find a color in pmap that exactly matches the one requested in prgb + * if it can't it allocates one. + * Starts looking at pentFirst + *pPixel, so if you want a specific pixel, + * load *pPixel with that value, otherwise set it to 0 + */ +int +FindColor(ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb * prgb, + Pixel * pPixel, int channel, int client, ColorCompareProcPtr comp) +{ + EntryPtr pent; + + Bool foundFree; + + Pixel pixel, Free = 0; + + int npix, count, *nump = NULL; + + Pixel **pixp = NULL, *ppix; + + xColorItem def; + + foundFree = FALSE; + + if ((pixel = *pPixel) >= size) + pixel = 0; + /* see if there is a match, and also look for a free entry */ + for (pent = pentFirst + pixel, count = size; --count >= 0;) { + if (pent->refcnt > 0) { + if ((*comp) (pent, prgb)) { + if (client >= 0) + pent->refcnt++; + *pPixel = pixel; + switch (channel) { + case REDMAP: + *pPixel <<= pmap->pVisual->offsetRed; + case PSEUDOMAP: + break; + case GREENMAP: + *pPixel <<= pmap->pVisual->offsetGreen; + break; + case BLUEMAP: + *pPixel <<= pmap->pVisual->offsetBlue; + break; + } + goto gotit; + } + } + else if (!foundFree && pent->refcnt == 0) { + Free = pixel; + foundFree = TRUE; + /* If we're initializing the colormap, then we are looking for + * the first free cell we can find, not to minimize the number + * of entries we use. So don't look any further. */ + if (pmap->flags & BeingCreated) + break; + } + pixel++; + if (pixel >= size) { + pent = pentFirst; + pixel = 0; + } + else + pent++; + } + + /* If we got here, we didn't find a match. If we also didn't find + * a free entry, we're out of luck. Otherwise, we'll usurp a free + * entry and fill it in */ + if (!foundFree) + return (BadAlloc); + pent = pentFirst + Free; + pent->fShared = FALSE; + pent->refcnt = (client >= 0) ? 1 : AllocTemporary; + + switch (channel) { + case PSEUDOMAP: + pent->co.local.red = prgb->red; + pent->co.local.green = prgb->green; + pent->co.local.blue = prgb->blue; + def.red = prgb->red; + def.green = prgb->green; + def.blue = prgb->blue; + def.flags = (DoRed | DoGreen | DoBlue); + if (client >= 0) + pmap->freeRed--; + def.pixel = Free; + break; + + case REDMAP: + pent->co.local.red = prgb->red; + def.red = prgb->red; + def.green = pmap->green[0].co.local.green; + def.blue = pmap->blue[0].co.local.blue; + def.flags = DoRed; + if (client >= 0) + pmap->freeRed--; + def.pixel = Free << pmap->pVisual->offsetRed; + break; + + case GREENMAP: + pent->co.local.green = prgb->green; + def.red = pmap->red[0].co.local.red; + def.green = prgb->green; + def.blue = pmap->blue[0].co.local.blue; + def.flags = DoGreen; + if (client >= 0) + pmap->freeGreen--; + def.pixel = Free << pmap->pVisual->offsetGreen; + break; + + case BLUEMAP: + pent->co.local.blue = prgb->blue; + def.red = pmap->red[0].co.local.red; + def.green = pmap->green[0].co.local.green; + def.blue = prgb->blue; + def.flags = DoBlue; + if (client >= 0) + pmap->freeBlue--; + def.pixel = Free << pmap->pVisual->offsetBlue; + break; + } + (*pmap->pScreen->StoreColors) (pmap, 1, &def); + pixel = Free; + *pPixel = def.pixel; + + gotit: + if (pmap->flags & BeingCreated || client == -1) + return (Success); + /* Now remember the pixel, for freeing later */ + switch (channel) { + case PSEUDOMAP: + case REDMAP: + nump = pmap->numPixelsRed; + pixp = pmap->clientPixelsRed; + break; + + case GREENMAP: + nump = pmap->numPixelsGreen; + pixp = pmap->clientPixelsGreen; + break; + + case BLUEMAP: + nump = pmap->numPixelsBlue; + pixp = pmap->clientPixelsBlue; + break; + } + npix = nump[client]; + ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel)); + if (!ppix) { + pent->refcnt--; + if (!pent->fShared) + switch (channel) { + case PSEUDOMAP: + case REDMAP: + pmap->freeRed++; + break; + case GREENMAP: + pmap->freeGreen++; + break; + case BLUEMAP: + pmap->freeBlue++; + break; + } + return (BadAlloc); + } + ppix[npix] = pixel; + pixp[client] = ppix; + nump[client]++; + + return (Success); +} + +/* Comparison functions -- passed to FindColor to determine if an + * entry is already the color we're looking for or not */ +static int +AllComp(EntryPtr pent, xrgb * prgb) +{ + if ((pent->co.local.red == prgb->red) && + (pent->co.local.green == prgb->green) && + (pent->co.local.blue == prgb->blue)) + return (1); + return (0); +} + +static int +RedComp(EntryPtr pent, xrgb * prgb) +{ + if (pent->co.local.red == prgb->red) + return (1); + return (0); +} + +static int +GreenComp(EntryPtr pent, xrgb * prgb) +{ + if (pent->co.local.green == prgb->green) + return (1); + return (0); +} + +static int +BlueComp(EntryPtr pent, xrgb * prgb) +{ + if (pent->co.local.blue == prgb->blue) + return (1); + return (0); +} + +/* Read the color value of a cell */ + +_X_EXPORT int +QueryColors(ColormapPtr pmap, int count, Pixel * ppixIn, xrgb * prgbList) +{ + Pixel *ppix, pixel; + + xrgb *prgb; + + VisualPtr pVisual; + + EntryPtr pent; + + Pixel i; + + int errVal = Success; + + pVisual = pmap->pVisual; + if ((pmap->class | DynamicClass) == DirectColor) { + int numred, numgreen, numblue; + + Pixel rgbbad; + + numred = NUMRED(pVisual); + numgreen = NUMGREEN(pVisual); + numblue = NUMBLUE(pVisual); + rgbbad = ~RGBMASK(pVisual); + for (ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) { + pixel = *ppix; + if (pixel & rgbbad) { + clientErrorValue = pixel; + errVal = BadValue; + continue; + } + i = (pixel & pVisual->redMask) >> pVisual->offsetRed; + if (i >= numred) { + clientErrorValue = pixel; + errVal = BadValue; + continue; + } + prgb->red = pmap->red[i].co.local.red; + i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; + if (i >= numgreen) { + clientErrorValue = pixel; + errVal = BadValue; + continue; + } + prgb->green = pmap->green[i].co.local.green; + i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (i >= numblue) { + clientErrorValue = pixel; + errVal = BadValue; + continue; + } + prgb->blue = pmap->blue[i].co.local.blue; + } + } + else { + for (ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) { + pixel = *ppix; + if (pixel >= pVisual->ColormapEntries) { + clientErrorValue = pixel; + errVal = BadValue; + } + else { + pent = (EntryPtr) & pmap->red[pixel]; + if (pent->fShared) { + prgb->red = pent->co.shco.red->color; + prgb->green = pent->co.shco.green->color; + prgb->blue = pent->co.shco.blue->color; + } + else { + prgb->red = pent->co.local.red; + prgb->green = pent->co.local.green; + prgb->blue = pent->co.local.blue; + } + } + } + } + return (errVal); +} + +static void +FreePixels(register ColormapPtr pmap, register int client) +{ + Pixel *ppix, *ppixStart; + + int class, n; + + class = pmap->class; + ppixStart = pmap->clientPixelsRed[client]; + if (class & DynamicClass) { + n = pmap->numPixelsRed[client]; + for (ppix = ppixStart; --n >= 0;) { + FreeCell(pmap, *ppix, REDMAP); + ppix++; + } + } + + free(ppixStart); + pmap->clientPixelsRed[client] = (Pixel *) NULL; + pmap->numPixelsRed[client] = 0; + if ((class | DynamicClass) == DirectColor) { + ppixStart = pmap->clientPixelsGreen[client]; + if (class & DynamicClass) + for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;) + FreeCell(pmap, *ppix++, GREENMAP); + free(ppixStart); + pmap->clientPixelsGreen[client] = (Pixel *) NULL; + pmap->numPixelsGreen[client] = 0; + + ppixStart = pmap->clientPixelsBlue[client]; + if (class & DynamicClass) + for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0;) + FreeCell(pmap, *ppix++, BLUEMAP); + free(ppixStart); + pmap->clientPixelsBlue[client] = (Pixel *) NULL; + pmap->numPixelsBlue[client] = 0; + } +} + +/** + * Frees all of a client's colors and cells. + * + * \param value must conform to DeleteType + * \unused fakeid + */ +int +FreeClientPixels(pointer value, XID fakeid) +{ + ColormapPtr pmap; + + colorResource *pcr = (colorResource *) value; + + pmap = (ColormapPtr) LookupIDByType(pcr->mid, RT_COLORMAP); + if (pmap) + FreePixels(pmap, pcr->client); + free(pcr); + return Success; +} + +int +AllocColorCells(int client, ColormapPtr pmap, int colors, int planes, + Bool contig, Pixel * ppix, Pixel * masks) +{ + Pixel rmask, gmask, bmask, *ppixFirst, r, g, b; + + int n, class; + + int ok; + + int oldcount; + + colorResource *pcr = (colorResource *) NULL; + + class = pmap->class; + if (!(class & DynamicClass)) + return (BadAlloc); /* Shouldn't try on this type */ + oldcount = pmap->numPixelsRed[client]; + if (pmap->class == DirectColor) + oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; + if (!oldcount && (CLIENT_ID(pmap->mid) != client)) { + pcr = malloc(sizeof(colorResource)); + if (!pcr) + return (BadAlloc); + } + + if (pmap->class == DirectColor) { + ok = AllocDirect(client, pmap, colors, planes, planes, planes, + contig, ppix, &rmask, &gmask, &bmask); + if (ok == Success) { + for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b) { + while (!(rmask & r)) + r += r; + while (!(gmask & g)) + g += g; + while (!(bmask & b)) + b += b; + *masks++ = r | g | b; + } + } + } + else { + ok = AllocPseudo(client, pmap, colors, planes, contig, ppix, &rmask, + &ppixFirst); + if (ok == Success) { + for (r = 1, n = planes; --n >= 0; r += r) { + while (!(rmask & r)) + r += r; + *masks++ = r; + } + } + } + + /* if this is the client's first pixels in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((ok == Success) && pcr) { + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer) pcr)) + ok = BadAlloc; + } + else if (pcr) + free(pcr); + + return (ok); +} + +int +AllocColorPlanes(int client, ColormapPtr pmap, int colors, + int r, int g, int b, Bool contig, Pixel * pixels, + Pixel * prmask, Pixel * pgmask, Pixel * pbmask) +{ + int ok; + + Pixel mask, *ppixFirst; + + Pixel shift; + + int i; + + int class; + + int oldcount; + + colorResource *pcr = (colorResource *) NULL; + + class = pmap->class; + if (!(class & DynamicClass)) + return (BadAlloc); /* Shouldn't try on this type */ + oldcount = pmap->numPixelsRed[client]; + if (class == DirectColor) + oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; + if (!oldcount && (CLIENT_ID(pmap->mid) != client)) { + pcr = malloc(sizeof(colorResource)); + if (!pcr) + return (BadAlloc); + } + + if (class == DirectColor) { + ok = AllocDirect(client, pmap, colors, r, g, b, contig, pixels, + prmask, pgmask, pbmask); + } + else { + /* Allocate the proper pixels */ + /* XXX This is sort of bad, because of contig is set, we force all + * r + g + b bits to be contiguous. Should only force contiguity + * per mask + */ + ok = AllocPseudo(client, pmap, colors, r + g + b, contig, pixels, + &mask, &ppixFirst); + + if (ok == Success) { + /* now split that mask into three */ + *prmask = *pgmask = *pbmask = 0; + shift = 1; + for (i = r; --i >= 0; shift += shift) { + while (!(mask & shift)) + shift += shift; + *prmask |= shift; + } + for (i = g; --i >= 0; shift += shift) { + while (!(mask & shift)) + shift += shift; + *pgmask |= shift; + } + for (i = b; --i >= 0; shift += shift) { + while (!(mask & shift)) + shift += shift; + *pbmask |= shift; + } + + /* set up the shared color cells */ + if (!AllocShared(pmap, pixels, colors, r, g, b, + *prmask, *pgmask, *pbmask, ppixFirst)) { + (void) FreeColors(pmap, client, colors, pixels, mask); + ok = BadAlloc; + } + } + } + + /* if this is the client's first pixels in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((ok == Success) && pcr) { + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer) pcr)) + ok = BadAlloc; + } + else if (pcr) + free(pcr); + + return (ok); +} + +static int +AllocDirect(int client, ColormapPtr pmap, int c, int r, int g, int b, + Bool contig, Pixel * pixels, Pixel * prmask, Pixel * pgmask, + Pixel * pbmask) +{ + Pixel *ppixRed, *ppixGreen, *ppixBlue; + + Pixel *ppix, *pDst, *p; + + int npix, npixR, npixG, npixB; + + Bool okR, okG, okB; + + Pixel *rpix = 0, *gpix = 0, *bpix = 0; + + npixR = c << r; + npixG = c << g; + npixB = c << b; + if ((r >= 32) || (g >= 32) || (b >= 32) || + (npixR > pmap->freeRed) || (npixR < c) || + (npixG > pmap->freeGreen) || (npixG < c) || + (npixB > pmap->freeBlue) || (npixB < c)) + return BadAlloc; + + /* start out with empty pixels */ + for (p = pixels; p < pixels + c; p++) + *p = 0; + + ppixRed = (Pixel *) ALLOCATE_LOCAL(npixR * sizeof(Pixel)); + ppixGreen = (Pixel *) ALLOCATE_LOCAL(npixG * sizeof(Pixel)); + ppixBlue = (Pixel *) ALLOCATE_LOCAL(npixB * sizeof(Pixel)); + if (!ppixRed || !ppixGreen || !ppixBlue) { + if (ppixBlue) + DEALLOCATE_LOCAL(ppixBlue); + if (ppixGreen) + DEALLOCATE_LOCAL(ppixGreen); + if (ppixRed) + DEALLOCATE_LOCAL(ppixRed); + return (BadAlloc); + } + + okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask); + okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask); + okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask); + + if (okR && okG && okB) { + rpix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (pmap->numPixelsRed[client] + (c << r)) * + sizeof(Pixel)); + if (rpix) + pmap->clientPixelsRed[client] = rpix; + gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client], + (pmap->numPixelsGreen[client] + (c << g)) * + sizeof(Pixel)); + if (gpix) + pmap->clientPixelsGreen[client] = gpix; + bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client], + (pmap->numPixelsBlue[client] + (c << b)) * + sizeof(Pixel)); + if (bpix) + pmap->clientPixelsBlue[client] = bpix; + } + + if (!okR || !okG || !okB || !rpix || !gpix || !bpix) { + if (okR) + for (ppix = ppixRed, npix = npixR; --npix >= 0; ppix++) + pmap->red[*ppix].refcnt = 0; + if (okG) + for (ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++) + pmap->green[*ppix].refcnt = 0; + if (okB) + for (ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++) + pmap->blue[*ppix].refcnt = 0; + DEALLOCATE_LOCAL(ppixBlue); + DEALLOCATE_LOCAL(ppixGreen); + DEALLOCATE_LOCAL(ppixRed); + return (BadAlloc); + } + + *prmask <<= pmap->pVisual->offsetRed; + *pgmask <<= pmap->pVisual->offsetGreen; + *pbmask <<= pmap->pVisual->offsetBlue; + + ppix = rpix + pmap->numPixelsRed[client]; + for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++) { + *ppix++ = *p; + if (p < ppixRed + c) + *pDst++ |= *p << pmap->pVisual->offsetRed; + } + pmap->numPixelsRed[client] += npixR; + pmap->freeRed -= npixR; + + ppix = gpix + pmap->numPixelsGreen[client]; + for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++) { + *ppix++ = *p; + if (p < ppixGreen + c) + *pDst++ |= *p << pmap->pVisual->offsetGreen; + } + pmap->numPixelsGreen[client] += npixG; + pmap->freeGreen -= npixG; + + ppix = bpix + pmap->numPixelsBlue[client]; + for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++) { + *ppix++ = *p; + if (p < ppixBlue + c) + *pDst++ |= *p << pmap->pVisual->offsetBlue; + } + pmap->numPixelsBlue[client] += npixB; + pmap->freeBlue -= npixB; + + for (pDst = pixels; pDst < pixels + c; pDst++) + *pDst |= ALPHAMASK(pmap->pVisual); + + DEALLOCATE_LOCAL(ppixBlue); + DEALLOCATE_LOCAL(ppixGreen); + DEALLOCATE_LOCAL(ppixRed); + + return (Success); +} + +static int +AllocPseudo(int client, ColormapPtr pmap, int c, int r, Bool contig, + Pixel * pixels, Pixel * pmask, Pixel ** pppixFirst) +{ + Pixel *ppix, *p, *pDst, *ppixTemp; + + int npix; + + Bool ok; + + npix = c << r; + if ((r >= 32) || (npix > pmap->freeRed) || (npix < c)) + return (BadAlloc); + if (!(ppixTemp = (Pixel *) ALLOCATE_LOCAL(npix * sizeof(Pixel)))) + return (BadAlloc); + ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask); + + if (ok) { + + /* all the allocated pixels are added to the client pixel list, + * but only the unique ones are returned to the client */ + ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (pmap->numPixelsRed[client] + + npix) * sizeof(Pixel)); + if (!ppix) { + for (p = ppixTemp; p < ppixTemp + npix; p++) + pmap->red[*p].refcnt = 0; + return (BadAlloc); + } + pmap->clientPixelsRed[client] = ppix; + ppix += pmap->numPixelsRed[client]; + *pppixFirst = ppix; + pDst = pixels; + for (p = ppixTemp; p < ppixTemp + npix; p++) { + *ppix++ = *p; + if (p < ppixTemp + c) + *pDst++ = *p; + } + pmap->numPixelsRed[client] += npix; + pmap->freeRed -= npix; + } + DEALLOCATE_LOCAL(ppixTemp); + return (ok ? Success : BadAlloc); +} + +/* Allocates count << planes pixels from colormap pmap for client. If + * contig, then the plane mask is made of consecutive bits. Returns + * all count << pixels in the array pixels. The first count of those + * pixels are the unique pixels. *pMask has the mask to Or with the + * unique pixels to get the rest of them. + * + * Returns True iff all pixels could be allocated + * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE + * (see AllocShared for why we care) + */ +static Bool +AllocCP(ColormapPtr pmap, EntryPtr pentFirst, int count, int planes, + Bool contig, Pixel * pixels, Pixel * pMask) +{ + EntryPtr ent; + + Pixel pixel, base, entries, maxp, save; + + int dplanes, found; + + Pixel *ppix; + + Pixel mask; + + Pixel finalmask; + + dplanes = pmap->pVisual->nplanes; + + /* Easy case. Allocate pixels only */ + if (planes == 0) { + /* allocate writable entries */ + ppix = pixels; + ent = pentFirst; + pixel = 0; + while (--count >= 0) { + /* Just find count unallocated cells */ + while (ent->refcnt) { + ent++; + pixel++; + } + ent->refcnt = AllocPrivate; + *ppix++ = pixel; + ent->fShared = FALSE; + } + *pMask = 0; + return (TRUE); + } + else if (planes > dplanes) { + return (FALSE); + } + + /* General case count pixels * 2 ^ planes cells to be allocated */ + + /* make room for new pixels */ + ent = pentFirst; + + /* first try for contiguous planes, since it's fastest */ + for (mask = (((Pixel) 1) << planes) - 1, base = 1, dplanes -= (planes - 1); + --dplanes >= 0; mask += mask, base += base) { + ppix = pixels; + found = 0; + pixel = 0; + entries = pmap->pVisual->ColormapEntries - mask; + while (pixel < entries) { + save = pixel; + maxp = pixel + mask + base; + /* check if all are free */ + while (pixel != maxp && ent[pixel].refcnt == 0) + pixel += base; + if (pixel == maxp) { + /* this one works */ + *ppix++ = save; + found++; + if (found == count) { + /* found enough, allocate them all */ + while (--count >= 0) { + pixel = pixels[count]; + maxp = pixel + mask; + while (1) { + ent[pixel].refcnt = AllocPrivate; + ent[pixel].fShared = FALSE; + if (pixel == maxp) + break; + pixel += base; + *ppix++ = pixel; + } + } + *pMask = mask; + return (TRUE); + } + } + pixel = save + 1; + if (pixel & mask) + pixel += mask; + } + } + + dplanes = pmap->pVisual->nplanes; + if (contig || planes == 1 || dplanes < 3) + return (FALSE); + + /* this will be very slow for large maps, need a better algorithm */ + + /* + we can generate the smallest and largest numbers that fits in dplanes + bits and contain exactly planes bits set as follows. First, we need to + check that it is possible to generate such a mask at all. + (Non-contiguous masks need one more bit than contiguous masks). Then + the smallest such mask consists of the rightmost planes-1 bits set, then + a zero, then a one in position planes + 1. The formula is + (3 << (planes-1)) -1 + The largest such masks consists of the leftmost planes-1 bits set, then + a zero, then a one bit in position dplanes-planes-1. If dplanes is + smaller than 32 (the number of bits in a word) then the formula is: + (1<>> + + */ + + finalmask = + (((((Pixel) 1) << (planes - 1)) - 1) << (dplanes - planes + 1)) + + (((Pixel) 1) << (dplanes - planes - 1)); + for (mask = (((Pixel) 3) << (planes - 1)) - 1; mask <= finalmask; mask++) { + /* next 3 magic statements count number of ones (HAKMEM #169) */ + pixel = (mask >> 1) & 033333333333; + pixel = mask - pixel - ((pixel >> 1) & 033333333333); + if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes) + continue; + ppix = pixels; + found = 0; + entries = pmap->pVisual->ColormapEntries - mask; + base = lowbit(mask); + for (pixel = 0; pixel < entries; pixel++) { + if (pixel & mask) + continue; + maxp = 0; + /* check if all are free */ + while (ent[pixel + maxp].refcnt == 0) { + GetNextBitsOrBreak(maxp, mask, base); + } + if ((maxp < mask) || (ent[pixel + mask].refcnt != 0)) + continue; + /* this one works */ + *ppix++ = pixel; + found++; + if (found < count) + continue; + /* found enough, allocate them all */ + while (--count >= 0) { + pixel = (pixels)[count]; + maxp = 0; + while (1) { + ent[pixel + maxp].refcnt = AllocPrivate; + ent[pixel + maxp].fShared = FALSE; + GetNextBitsOrBreak(maxp, mask, base); + *ppix++ = pixel + maxp; + } + } + + *pMask = mask; + return (TRUE); + } + } + return (FALSE); +} + +/** + * + * \param ppixFirst First of the client's new pixels + */ +static Bool +AllocShared(ColormapPtr pmap, Pixel * ppix, int c, int r, int g, int b, + Pixel rmask, Pixel gmask, Pixel bmask, Pixel * ppixFirst) +{ + Pixel *pptr, *cptr; + + int npix, z, npixClientNew, npixShared; + + Pixel basemask, base, bits, common; + + SHAREDCOLOR *pshared, **ppshared, **psharedList; + + npixClientNew = c << (r + g + b); + npixShared = (c << r) + (c << g) + (c << b); + psharedList = (SHAREDCOLOR **) ALLOCATE_LOCAL(npixShared * + sizeof(SHAREDCOLOR *)); + if (!psharedList) + return FALSE; + ppshared = psharedList; + for (z = npixShared; --z >= 0;) { + if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR)))) { + for (z++; z < npixShared; z++) + free(ppshared[z]); + return FALSE; + } + } + for (pptr = ppix, npix = c; --npix >= 0; pptr++) { + basemask = ~(gmask | bmask); + common = *pptr & basemask; + if (rmask) { + bits = 0; + base = lowbit(rmask); + while (1) { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == (common | bits)) { + pmap->red[*cptr].fShared = TRUE; + pmap->red[*cptr].co.shco.red = pshared; + } + } + GetNextBitsOrBreak(bits, rmask, base); + } + } + else { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == common) { + pmap->red[*cptr].fShared = TRUE; + pmap->red[*cptr].co.shco.red = pshared; + } + } + } + basemask = ~(rmask | bmask); + common = *pptr & basemask; + if (gmask) { + bits = 0; + base = lowbit(gmask); + while (1) { + pshared = *ppshared++; + pshared->refcnt = 1 << (r + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == (common | bits)) { + pmap->red[*cptr].co.shco.green = pshared; + } + } + GetNextBitsOrBreak(bits, gmask, base); + } + } + else { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == common) { + pmap->red[*cptr].co.shco.green = pshared; + } + } + } + basemask = ~(rmask | gmask); + common = *pptr & basemask; + if (bmask) { + bits = 0; + base = lowbit(bmask); + while (1) { + pshared = *ppshared++; + pshared->refcnt = 1 << (r + g); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == (common | bits)) { + pmap->red[*cptr].co.shco.blue = pshared; + } + } + GetNextBitsOrBreak(bits, bmask, base); + } + } + else { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) { + if ((*cptr & basemask) == common) { + pmap->red[*cptr].co.shco.blue = pshared; + } + } + } + } + DEALLOCATE_LOCAL(psharedList); + return TRUE; +} + +/** FreeColors + * Free colors and/or cells (probably slow for large numbers) + */ +_X_EXPORT int +FreeColors(ColormapPtr pmap, int client, int count, Pixel * pixels, Pixel mask) +{ + int rval, result, class; + + Pixel rmask; + + class = pmap->class; + if (pmap->flags & AllAllocated) + return (BadAccess); + if ((class | DynamicClass) == DirectColor) { + rmask = mask & RGBMASK(pmap->pVisual); + result = FreeCo(pmap, client, REDMAP, count, pixels, + mask & pmap->pVisual->redMask); + /* If any of the three calls fails, we must report that, if more + * than one fails, it's ok that we report the last one */ + rval = FreeCo(pmap, client, GREENMAP, count, pixels, + mask & pmap->pVisual->greenMask); + if (rval != Success) + result = rval; + rval = FreeCo(pmap, client, BLUEMAP, count, pixels, + mask & pmap->pVisual->blueMask); + if (rval != Success) + result = rval; + } + else { + rmask = mask & ((((Pixel) 1) << pmap->pVisual->nplanes) - 1); + result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask); + } + if ((mask != rmask) && count) { + clientErrorValue = *pixels | mask; + result = BadValue; + } + /* XXX should worry about removing any RT_CMAPENTRY resource */ + return (result); +} + +/** + * Helper for FreeColors -- frees all combinations of *newpixels and mask bits + * which the client has allocated in channel colormap cells of pmap. + * doesn't change newpixels if it doesn't need to + * + * \param pmap which colormap head + * \param color which sub-map, eg, RED, BLUE, PSEUDO + * \param npixIn number of pixels passed in + * \param ppixIn number of base pixels + * \param mask mask client gave us + */ +static int +FreeCo(ColormapPtr pmap, int client, int color, int npixIn, Pixel * ppixIn, + Pixel mask) +{ + Pixel *ppixClient, pixTest; + + int npixClient, npixNew, npix; + + Pixel bits, base, cmask, rgbbad; + + Pixel *pptr, *cptr; + + int n, zapped; + + int errVal = Success; + + int offset, numents; + + if (npixIn == 0) + return (errVal); + bits = 0; + zapped = 0; + base = lowbit(mask); + + switch (color) { + case REDMAP: + cmask = pmap->pVisual->redMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetRed; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsRed[client]; + npixClient = pmap->numPixelsRed[client]; + break; + case GREENMAP: + cmask = pmap->pVisual->greenMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetGreen; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsGreen[client]; + npixClient = pmap->numPixelsGreen[client]; + break; + case BLUEMAP: + cmask = pmap->pVisual->blueMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetBlue; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsBlue[client]; + npixClient = pmap->numPixelsBlue[client]; + break; + default: /* so compiler can see that everything gets initialized */ + case PSEUDOMAP: + cmask = ~((Pixel) 0); + rgbbad = 0; + offset = 0; + numents = pmap->pVisual->ColormapEntries; + ppixClient = pmap->clientPixelsRed[client]; + npixClient = pmap->numPixelsRed[client]; + break; + } + + /* zap all pixels which match */ + while (1) { + /* go through pixel list */ + for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++) { + pixTest = ((*pptr | bits) & cmask) >> offset; + if ((pixTest >= numents) || (*pptr & rgbbad)) { + clientErrorValue = *pptr | bits; + errVal = BadValue; + continue; + } + + /* find match in client list */ + for (cptr = ppixClient, npix = npixClient; + --npix >= 0 && *cptr != pixTest; cptr++); + + if (npix >= 0) { + if (pmap->class & DynamicClass) { + FreeCell(pmap, pixTest, color); + } + *cptr = ~((Pixel) 0); + zapped++; + } + else + errVal = BadAccess; + } + /* generate next bits value */ + GetNextBitsOrBreak(bits, mask, base); + } + + /* delete freed pixels from client pixel list */ + if (zapped) { + npixNew = npixClient - zapped; + if (npixNew) { + /* Since the list can only get smaller, we can do a copy in + * place and then realloc to a smaller size */ + pptr = cptr = ppixClient; + + /* If we have all the new pixels, we don't have to examine the + * rest of the old ones */ + for (npix = 0; npix < npixNew; cptr++) { + if (*cptr != ~((Pixel) 0)) { + *pptr++ = *cptr; + npix++; + } + } + pptr = (Pixel *) realloc(ppixClient, npixNew * sizeof(Pixel)); + if (pptr) + ppixClient = pptr; + npixClient = npixNew; + } + else { + npixClient = 0; + free(ppixClient); + ppixClient = (Pixel *) NULL; + } + switch (color) { + case PSEUDOMAP: + case REDMAP: + pmap->clientPixelsRed[client] = ppixClient; + pmap->numPixelsRed[client] = npixClient; + break; + case GREENMAP: + pmap->clientPixelsGreen[client] = ppixClient; + pmap->numPixelsGreen[client] = npixClient; + break; + case BLUEMAP: + pmap->clientPixelsBlue[client] = ppixClient; + pmap->numPixelsBlue[client] = npixClient; + break; + } + } + return (errVal); +} + +/* Redefine color values */ +_X_EXPORT int +StoreColors(ColormapPtr pmap, int count, xColorItem * defs) +{ + Pixel pix; + + xColorItem *pdef; + + EntryPtr pent, pentT, pentLast; + + VisualPtr pVisual; + + SHAREDCOLOR *pred, *pgreen, *pblue; + + int n, ChgRed, ChgGreen, ChgBlue, idef; + + int class, errVal = Success; + + int ok; + + class = pmap->class; + if (!(class & DynamicClass) && !(pmap->flags & BeingCreated)) { + return (BadAccess); + } + pVisual = pmap->pVisual; + + idef = 0; + if ((class | DynamicClass) == DirectColor) { + int numred, numgreen, numblue; + + Pixel rgbbad; + + numred = NUMRED(pVisual); + numgreen = NUMGREEN(pVisual); + numblue = NUMBLUE(pVisual); + rgbbad = ~RGBMASK(pVisual); + for (pdef = defs, n = 0; n < count; pdef++, n++) { + ok = TRUE; + (*pmap->pScreen->ResolveColor) + (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); + + if (pdef->pixel & rgbbad) { + errVal = BadValue; + clientErrorValue = pdef->pixel; + continue; + } + pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed; + if (pix >= numred) { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->red[pix].refcnt != AllocPrivate) { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoRed) { + pmap->red[pix].co.local.red = pdef->red; + } + else { + pdef->red = pmap->red[pix].co.local.red; + } + + pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen; + if (pix >= numgreen) { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->green[pix].refcnt != AllocPrivate) { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoGreen) { + pmap->green[pix].co.local.green = pdef->green; + } + else { + pdef->green = pmap->green[pix].co.local.green; + } + + pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (pix >= numblue) { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->blue[pix].refcnt != AllocPrivate) { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoBlue) { + pmap->blue[pix].co.local.blue = pdef->blue; + } + else { + pdef->blue = pmap->blue[pix].co.local.blue; + } + /* If this is an o.k. entry, then it gets added to the list + * to be sent to the hardware. If not, skip it. Once we've + * skipped one, we have to copy all the others. + */ + if (ok) { + if (idef != n) + defs[idef] = defs[n]; + idef++; + } + else + clientErrorValue = pdef->pixel; + } + } + else { + for (pdef = defs, n = 0; n < count; pdef++, n++) { + + ok = TRUE; + if (pdef->pixel >= pVisual->ColormapEntries) { + clientErrorValue = pdef->pixel; + errVal = BadValue; + ok = FALSE; + } + else if (pmap->red[pdef->pixel].refcnt != AllocPrivate) { + errVal = BadAccess; + ok = FALSE; + } + + /* If this is an o.k. entry, then it gets added to the list + * to be sent to the hardware. If not, skip it. Once we've + * skipped one, we have to copy all the others. + */ + if (ok) { + if (idef != n) + defs[idef] = defs[n]; + idef++; + } + else + continue; + + (*pmap->pScreen->ResolveColor) + (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); + + pent = &pmap->red[pdef->pixel]; + + if (pdef->flags & DoRed) { + if (pent->fShared) { + pent->co.shco.red->color = pdef->red; + if (pent->co.shco.red->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.red = pdef->red; + } + else { + if (pent->fShared) + pdef->red = pent->co.shco.red->color; + else + pdef->red = pent->co.local.red; + } + if (pdef->flags & DoGreen) { + if (pent->fShared) { + pent->co.shco.green->color = pdef->green; + if (pent->co.shco.green->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.green = pdef->green; + } + else { + if (pent->fShared) + pdef->green = pent->co.shco.green->color; + else + pdef->green = pent->co.local.green; + } + if (pdef->flags & DoBlue) { + if (pent->fShared) { + pent->co.shco.blue->color = pdef->blue; + if (pent->co.shco.blue->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.blue = pdef->blue; + } + else { + if (pent->fShared) + pdef->blue = pent->co.shco.blue->color; + else + pdef->blue = pent->co.local.blue; + } + + if (!ok) { + /* have to run through the colormap and change anybody who + * shares this value */ + pred = pent->co.shco.red; + pgreen = pent->co.shco.green; + pblue = pent->co.shco.blue; + ChgRed = pdef->flags & DoRed; + ChgGreen = pdef->flags & DoGreen; + ChgBlue = pdef->flags & DoBlue; + pentLast = pmap->red + pVisual->ColormapEntries; + + for (pentT = pmap->red; pentT < pentLast; pentT++) { + if (pentT->fShared && (pentT != pent)) { + xColorItem defChg; + + /* There are, alas, devices in this world too dumb + * to read their own hardware colormaps. Sick, but + * true. So we're going to be really nice and load + * the xColorItem with the proper value for all the + * fields. We will only set the flags for those + * fields that actually change. Smart devices can + * arrange to change only those fields. Dumb devices + * can rest assured that we have provided for them, + * and can change all three fields */ + + defChg.flags = 0; + if (ChgRed && pentT->co.shco.red == pred) { + defChg.flags |= DoRed; + } + if (ChgGreen && pentT->co.shco.green == pgreen) { + defChg.flags |= DoGreen; + } + if (ChgBlue && pentT->co.shco.blue == pblue) { + defChg.flags |= DoBlue; + } + if (defChg.flags != 0) { + defChg.pixel = pentT - pmap->red; + defChg.red = pentT->co.shco.red->color; + defChg.green = pentT->co.shco.green->color; + defChg.blue = pentT->co.shco.blue->color; + (*pmap->pScreen->StoreColors) (pmap, 1, &defChg); + } + } + } + + } + } + } + /* Note that we use idef, the count of acceptable entries, and not + * count, the count of proposed entries */ + if (idef != 0) + (*pmap->pScreen->StoreColors) (pmap, idef, defs); + return (errVal); +} + +int +IsMapInstalled(Colormap map, WindowPtr pWin) +{ + Colormap *pmaps; + + int imap, nummaps, found; + + pmaps = + (Colormap *) ALLOCATE_LOCAL(pWin->drawable.pScreen->maxInstalledCmaps * + sizeof(Colormap)); + if (!pmaps) + return (FALSE); + nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pWin->drawable.pScreen, pmaps); + found = FALSE; + for (imap = 0; imap < nummaps; imap++) { + if (pmaps[imap] == map) { + found = TRUE; + break; + } + } + DEALLOCATE_LOCAL(pmaps); + return (found); +} diff --git a/dix/cursor.c b/dix/cursor.c new file mode 100644 index 0000000..a132e99 --- /dev/null +++ b/dix/cursor.c @@ -0,0 +1,442 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "servermd.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "dixfontstr.h" +#include "opaque.h" + +typedef struct _GlyphShare { + FontPtr font; + unsigned short sourceChar; + unsigned short maskChar; + CursorBitsPtr bits; + struct _GlyphShare *next; +} GlyphShare, *GlyphSharePtr; + +static GlyphSharePtr sharedGlyphs = (GlyphSharePtr) NULL; + +static CARD32 cursorSerial; + +static void +FreeCursorBits(CursorBitsPtr bits) +{ + if (--bits->refcnt > 0) + return; + free(bits->source); + free(bits->mask); +#ifdef ARGB_CURSOR + free(bits->argb); +#endif + if (bits->refcnt == 0) { + GlyphSharePtr *prev, this; + + for (prev = &sharedGlyphs; + (this = *prev) && (this->bits != bits); prev = &this->next); + if (this) { + *prev = this->next; + CloseFont(this->font, (Font) 0); + free(this); + } + free(bits); + } +} + +/** + * To be called indirectly by DeleteResource; must use exactly two args. + * + * \param value must conform to DeleteType + */ +_X_EXPORT int +FreeCursor(pointer value, XID cid) +{ + int nscr; + + CursorPtr pCurs = (CursorPtr) value; + + ScreenPtr pscr; + + if (--pCurs->refcnt > 0) + return (Success); + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + (void) (*pscr->UnrealizeCursor) (pscr, pCurs); + } + FreeCursorBits(pCurs->bits); + free(pCurs); + return (Success); +} + +/* + * We check for empty cursors so that we won't have to display them + */ +static void +CheckForEmptyMask(CursorBitsPtr bits) +{ + unsigned char *msk = bits->mask; + + int n = BitmapBytePad(bits->width) * bits->height; + + bits->emptyMask = FALSE; + while (n--) + if (*(msk++) != 0) + return; +#ifdef ARGB_CURSOR + if (bits->argb) { + CARD32 *argb = bits->argb; + + int n = bits->width * bits->height; + + while (n--) + if (*argb++ & 0xff000000) + return; + } +#endif + bits->emptyMask = TRUE; +} + +/** + * does nothing about the resource table, just creates the data structure. + * does not copy the src and mask bits + * + * \param psrcbits server-defined padding + * \param pmaskbits server-defined padding + * \param argb no padding + */ +CursorPtr +AllocCursorARGB(unsigned char *psrcbits, unsigned char *pmaskbits, CARD32 *argb, + CursorMetricPtr cm, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue) +{ + CursorBitsPtr bits; + + CursorPtr pCurs; + + int nscr; + + ScreenPtr pscr; + + pCurs = malloc(sizeof(CursorRec) + sizeof(CursorBits)); + if (!pCurs) { + free(psrcbits); + free(pmaskbits); + return (CursorPtr) NULL; + } + bits = (CursorBitsPtr) ((char *) pCurs + sizeof(CursorRec)); + bits->source = psrcbits; + bits->mask = pmaskbits; +#ifdef ARGB_CURSOR + bits->argb = argb; +#endif + bits->width = cm->width; + bits->height = cm->height; + bits->xhot = cm->xhot; + bits->yhot = cm->yhot; + bits->refcnt = -1; + CheckForEmptyMask(bits); + + pCurs->bits = bits; + pCurs->refcnt = 1; + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + /* + * realize the cursor for every screen + */ + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + if (!(*pscr->RealizeCursor) (pscr, pCurs)) { + while (--nscr >= 0) { + pscr = screenInfo.screens[nscr]; + (*pscr->UnrealizeCursor) (pscr, pCurs); + } + FreeCursorBits(bits); + free(pCurs); + return (CursorPtr) NULL; + } + } + return pCurs; +} + +/** + * + * \param psrcbits server-defined padding + * \param pmaskbits server-defined padding + */ +CursorPtr +AllocCursor(unsigned char *psrcbits, unsigned char *pmaskbits, + CursorMetricPtr cm, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue) +{ + return AllocCursorARGB(psrcbits, pmaskbits, (CARD32 *) 0, cm, + foreRed, foreGreen, foreBlue, + backRed, backGreen, backBlue); +} + +int +AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client) +{ + FontPtr sourcefont, maskfont; + + unsigned char *srcbits; + + unsigned char *mskbits; + + CursorMetricRec cm; + + int res; + + CursorBitsPtr bits; + + CursorPtr pCurs = NULL; + + int nscr; + + ScreenPtr pscr; + + GlyphSharePtr pShare; + + sourcefont = (FontPtr) SecurityLookupIDByType(client, source, RT_FONT, + SecurityReadAccess); + maskfont = (FontPtr) SecurityLookupIDByType(client, mask, RT_FONT, + SecurityReadAccess); + + if (!sourcefont) { + client->errorValue = source; + return (BadFont); + } + if (!maskfont && (mask != None)) { + client->errorValue = mask; + return (BadFont); + } + if (sourcefont != maskfont) + pShare = (GlyphSharePtr) NULL; + else { + for (pShare = sharedGlyphs; + pShare && + ((pShare->font != sourcefont) || + (pShare->sourceChar != sourceChar) || + (pShare->maskChar != maskChar)); pShare = pShare->next); + } + if (pShare) { + pCurs = malloc(sizeof(CursorRec)); + if (!pCurs) + return BadAlloc; + bits = pShare->bits; + bits->refcnt++; + } + else { + if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm)) { + client->errorValue = sourceChar; + return BadValue; + } + if (!maskfont) { + long n; + + unsigned char *mskptr; + + n = BitmapBytePad(cm.width) * (long) cm.height; + mskptr = mskbits = malloc(n); + if (!mskptr) + return BadAlloc; + while (--n >= 0) + *mskptr++ = ~0; + } + else { + if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) { + client->errorValue = maskChar; + return BadValue; + } + if ((res = + ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits)) != 0) + return res; + } + if ((res = + ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits)) != 0) { + free(mskbits); + return res; + } + if (sourcefont != maskfont) { + pCurs = malloc(sizeof(CursorRec) + sizeof(CursorBits)); + if (pCurs) + bits = (CursorBitsPtr) ((char *) pCurs + sizeof(CursorRec)); + else + bits = (CursorBitsPtr) NULL; + } + else { + pCurs = malloc(sizeof(CursorRec)); + if (pCurs) + bits = malloc(sizeof(CursorBits)); + else + bits = (CursorBitsPtr) NULL; + } + if (!bits) { + free(pCurs); + free(mskbits); + free(srcbits); + return BadAlloc; + } + bits->source = srcbits; + bits->mask = mskbits; +#ifdef ARGB_CURSOR + bits->argb = 0; +#endif + bits->width = cm.width; + bits->height = cm.height; + bits->xhot = cm.xhot; + bits->yhot = cm.yhot; + if (sourcefont != maskfont) + bits->refcnt = -1; + else { + bits->refcnt = 1; + pShare = malloc(sizeof(GlyphShare)); + if (!pShare) { + FreeCursorBits(bits); + free(pCurs); + return BadAlloc; + } + pShare->font = sourcefont; + sourcefont->refcnt++; + pShare->sourceChar = sourceChar; + pShare->maskChar = maskChar; + pShare->bits = bits; + pShare->next = sharedGlyphs; + sharedGlyphs = pShare; + } + } + CheckForEmptyMask(bits); + pCurs->bits = bits; + pCurs->refcnt = 1; + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + /* + * realize the cursor for every screen + */ + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + if (!(*pscr->RealizeCursor) (pscr, pCurs)) { + while (--nscr >= 0) { + pscr = screenInfo.screens[nscr]; + (*pscr->UnrealizeCursor) (pscr, pCurs); + } + FreeCursorBits(pCurs->bits); + free(pCurs); + return BadAlloc; + } + } + *ppCurs = pCurs; + return Success; +} + +/** CreateRootCursor + * + * look up the name of a font + * open the font + * add the font to the resource table + * make a cursor from the glyphs + * add the cursor to the resource table + *************************************************************/ + +CursorPtr +CreateRootCursor(char *pfilename, unsigned glyph) +{ + CursorPtr curs; + + FontPtr cursorfont; + + int err; + + XID fontID; + + fontID = FakeClientID(0); + err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, + (unsigned) strlen(pfilename), pfilename); + if (err != Success) + return NullCursor; + + cursorfont = (FontPtr) LookupIDByType(fontID, RT_FONT); + if (!cursorfont) + return NullCursor; + if (AllocGlyphCursor(fontID, glyph, fontID, glyph + 1, + 0, 0, 0, ~0, ~0, ~0, &curs, serverClient) != Success) + return NullCursor; + + if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer) curs)) + return NullCursor; + + return curs; +} diff --git a/dix/devices.c b/dix/devices.c new file mode 100644 index 0000000..ca62f49 --- /dev/null +++ b/dix/devices.c @@ -0,0 +1,1363 @@ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "resource.h" +#include +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "site.h" +#ifndef XKB_IN_SERVER +#define XKB_IN_SERVER +#endif + +#include "dispatch.h" +#include "swaprep.h" +#include "dixevents.h" + +DeviceIntPtr +AddInputDevice(DeviceProc deviceProc, Bool autoStart) +{ + DeviceIntPtr dev; + + if (inputInfo.numDevices >= MAX_DEVICES) + return (DeviceIntPtr) NULL; + dev = malloc(sizeof(DeviceIntRec)); + if (!dev) + return (DeviceIntPtr) NULL; + dev->name = (char *) NULL; + dev->type = 0; + dev->id = inputInfo.numDevices; + inputInfo.numDevices++; + dev->public.on = FALSE; + dev->public.processInputProc = (ProcessInputProc) NoopDDA; + dev->public.realInputProc = (ProcessInputProc) NoopDDA; + dev->public.enqueueInputProc = EnqueueEvent; + dev->deviceProc = deviceProc; + dev->startup = autoStart; + dev->sync.frozen = FALSE; + dev->sync.other = NullGrab; + dev->sync.state = NOT_GRABBED; + dev->sync.event = (xEvent *) NULL; + dev->sync.evcount = 0; + dev->grab = NullGrab; + dev->grabTime = currentTime; + dev->fromPassiveGrab = FALSE; + dev->key = (KeyClassPtr) NULL; + dev->valuator = (ValuatorClassPtr) NULL; + dev->button = (ButtonClassPtr) NULL; + dev->focus = (FocusClassPtr) NULL; + dev->proximity = (ProximityClassPtr) NULL; + dev->kbdfeed = (KbdFeedbackPtr) NULL; + dev->ptrfeed = (PtrFeedbackPtr) NULL; + dev->intfeed = (IntegerFeedbackPtr) NULL; + dev->stringfeed = (StringFeedbackPtr) NULL; + dev->bell = (BellFeedbackPtr) NULL; + dev->leds = (LedFeedbackPtr) NULL; + dev->next = inputInfo.off_devices; + dev->nPrivates = 0; + dev->devPrivates = NULL; + dev->unwrapProc = NULL; + inputInfo.off_devices = dev; + return dev; +} + +Bool +EnableDevice(register DeviceIntPtr dev) +{ + DeviceIntPtr *prev; + + for (prev = &inputInfo.off_devices; + *prev && (*prev != dev); prev = &(*prev)->next); + if ((*prev != dev) || !dev->inited || + ((*dev->deviceProc) (dev, DEVICE_ON) != Success)) + return FALSE; + *prev = dev->next; + dev->next = inputInfo.devices; + inputInfo.devices = dev; + return TRUE; +} + +Bool +DisableDevice(register DeviceIntPtr dev) +{ + DeviceIntPtr *prev; + + for (prev = &inputInfo.devices; + *prev && (*prev != dev); prev = &(*prev)->next); + if (*prev != dev) + return FALSE; + (void) (*dev->deviceProc) (dev, DEVICE_OFF); + *prev = dev->next; + dev->next = inputInfo.off_devices; + inputInfo.off_devices = dev; + return TRUE; +} + +int +InitAndStartDevices() +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + dev->inited = ((*dev->deviceProc) (dev, DEVICE_INIT) == Success); + for (dev = inputInfo.off_devices; dev; dev = next) { + next = dev->next; + if (dev->inited && dev->startup) + (void) EnableDevice(dev); + } + for (dev = inputInfo.devices; + dev && (dev != inputInfo.keyboard); dev = dev->next); + if (!dev || (dev != inputInfo.keyboard)) { + ErrorF("No core keyboard\n"); + return BadImplementation; + } + for (dev = inputInfo.devices; + dev && (dev != inputInfo.pointer); dev = dev->next); + if (!dev || (dev != inputInfo.pointer)) { + ErrorF("No core pointer\n"); + return BadImplementation; + } + return Success; +} + +static void +CloseDevice(register DeviceIntPtr dev) +{ + KbdFeedbackPtr k, knext; + + PtrFeedbackPtr p, pnext; + + IntegerFeedbackPtr i, inext; + + StringFeedbackPtr s, snext; + + BellFeedbackPtr b, bnext; + + LedFeedbackPtr l, lnext; + + if (dev->inited) + (void) (*dev->deviceProc) (dev, DEVICE_CLOSE); + free(dev->name); + if (dev->key) { + free(dev->key->curKeySyms.map); + free(dev->key->modifierKeyMap); + free(dev->key); + } + free(dev->valuator); + free(dev->button); + if (dev->focus) { + free(dev->focus->trace); + free(dev->focus); + } + free(dev->proximity); + for (k = dev->kbdfeed; k; k = knext) { + knext = k->next; + free(k); + } + for (p = dev->ptrfeed; p; p = pnext) { + pnext = p->next; + free(p); + } + for (i = dev->intfeed; i; i = inext) { + inext = i->next; + free(i); + } + for (s = dev->stringfeed; s; s = snext) { + snext = s->next; + free(s->ctrl.symbols_supported); + free(s->ctrl.symbols_displayed); + free(s); + } + for (b = dev->bell; b; b = bnext) { + bnext = b->next; + free(b); + } + for (l = dev->leds; l; l = lnext) { + lnext = l->next; + free(l); + } + free(dev->sync.event); + free(dev); +} + +void +CloseDownDevices() +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.devices; dev; dev = next) { + next = dev->next; + CloseDevice(dev); + } + for (dev = inputInfo.off_devices; dev; dev = next) { + next = dev->next; + CloseDevice(dev); + } + inputInfo.devices = NULL; + inputInfo.off_devices = NULL; + inputInfo.keyboard = NULL; + inputInfo.pointer = NULL; +} + +void +RemoveDevice(register DeviceIntPtr dev) +{ + DeviceIntPtr prev, tmp, next; + + prev = NULL; + for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + CloseDevice(tmp); + if (prev == NULL) + inputInfo.devices = next; + else + prev->next = next; + inputInfo.numDevices--; + if (inputInfo.keyboard == tmp) + inputInfo.keyboard = NULL; + else if (inputInfo.pointer == tmp) + inputInfo.pointer = NULL; + + return; + } + } + + prev = NULL; + for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + CloseDevice(tmp); + if (prev == NULL) + inputInfo.off_devices = next; + else + prev->next = next; + inputInfo.numDevices--; + if (inputInfo.keyboard == tmp) + inputInfo.keyboard = NULL; + else if (inputInfo.pointer == tmp) + inputInfo.pointer = NULL; + + return; + } + } + ErrorF("Internal Error! Attempt to remove a non-existent device\n"); + return; +} + +int +NumMotionEvents() +{ + return inputInfo.pointer->valuator->numMotionEvents; +} + +void +RegisterPointerDevice(DeviceIntPtr device) +{ + inputInfo.pointer = device; + + device->public.processInputProc = ProcessPointerEvent; + device->public.realInputProc = ProcessPointerEvent; + device->ActivateGrab = ActivatePointerGrab; + device->DeactivateGrab = DeactivatePointerGrab; + if (!device->name) { + char *p = "pointer"; + + device->name = malloc(strlen(p) + 1); + strcpy(device->name, p); + } +} + +void +RegisterKeyboardDevice(DeviceIntPtr device) +{ + inputInfo.keyboard = device; + device->public.processInputProc = ProcessKeyboardEvent; + device->public.realInputProc = ProcessKeyboardEvent; + device->ActivateGrab = ActivateKeyboardGrab; + device->DeactivateGrab = DeactivateKeyboardGrab; + if (!device->name) { + char *k = "keyboard"; + + device->name = malloc(strlen(k) + 1); + strcpy(device->name, k); + } +} + +_X_EXPORT DevicePtr +LookupKeyboardDevice() +{ + return inputInfo.keyboard ? &inputInfo.keyboard->public : NULL; +} + +_X_EXPORT DevicePtr +LookupPointerDevice() +{ + return inputInfo.pointer ? &inputInfo.pointer->public : NULL; +} + +DevicePtr +LookupDevice(int id) +{ + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->id == (CARD8) id) + return (DevicePtr) dev; + } + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + if (dev->id == (CARD8) id) + return (DevicePtr) dev; + } + return NULL; +} + +void +QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) +{ + if (inputInfo.keyboard) { + *minCode = inputInfo.keyboard->key->curKeySyms.minKeyCode; + *maxCode = inputInfo.keyboard->key->curKeySyms.maxKeyCode; + } +} + +Bool +SetKeySymsMap(register KeySymsPtr dst, register KeySymsPtr src) +{ + int i, j; + + int rowDif = src->minKeyCode - dst->minKeyCode; + + /* if keysym map size changes, grow map first */ + + if (src->mapWidth < dst->mapWidth) { + for (i = src->minKeyCode; i <= src->maxKeyCode; i++) { +#define SI(r, c) (((r-src->minKeyCode)*src->mapWidth) + (c)) +#define DI(r, c) (((r - dst->minKeyCode)*dst->mapWidth) + (c)) + for (j = 0; j < src->mapWidth; j++) + dst->map[DI(i, j)] = src->map[SI(i, j)]; + for (j = src->mapWidth; j < dst->mapWidth; j++) + dst->map[DI(i, j)] = NoSymbol; +#undef SI +#undef DI + } + return TRUE; + } + else if (src->mapWidth > dst->mapWidth) { + KeySym *map; + + int bytes = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + map = malloc(bytes); + if (!map) + return FALSE; + bzero((char *) map, bytes); + if (dst->map) { + for (i = 0; i <= dst->maxKeyCode - dst->minKeyCode; i++) + memmove((char *) &map[i * src->mapWidth], + (char *) &dst->map[i * dst->mapWidth], + dst->mapWidth * sizeof(KeySym)); + free(dst->map); + } + dst->mapWidth = src->mapWidth; + dst->map = map; + } + memmove((char *) &dst->map[rowDif * dst->mapWidth], + (char *) src->map, + (int) (src->maxKeyCode - src->minKeyCode + 1) * + dst->mapWidth * sizeof(KeySym)); + return TRUE; +} + +static Bool +InitModMap(register KeyClassPtr keyc) +{ + int i, j; + + CARD8 keysPerModifier[8]; + + CARD8 mask; + + keyc->maxKeysPerModifier = 0; + for (i = 0; i < 8; i++) + keysPerModifier[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0, mask = 1; j < 8; j++, mask <<= 1) { + if (mask & keyc->modifierMap[i]) { + if (++keysPerModifier[j] > keyc->maxKeysPerModifier) + keyc->maxKeysPerModifier = keysPerModifier[j]; + } + } + } + keyc->modifierKeyMap = malloc(8 * keyc->maxKeysPerModifier); + if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier) + return (FALSE); + bzero((char *) keyc->modifierKeyMap, 8 * (int) keyc->maxKeysPerModifier); + for (i = 0; i < 8; i++) + keysPerModifier[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0, mask = 1; j < 8; j++, mask <<= 1) { + if (mask & keyc->modifierMap[i]) { + keyc->modifierKeyMap[(j * keyc->maxKeysPerModifier) + + keysPerModifier[j]] = i; + keysPerModifier[j]++; + } + } + } + return TRUE; +} + +_X_EXPORT Bool +InitKeyClassDeviceStruct(DeviceIntPtr dev, KeySymsPtr pKeySyms, + CARD8 pModifiers[]) +{ + int i; + + KeyClassPtr keyc; + + keyc = malloc(sizeof(KeyClassRec)); + if (!keyc) + return FALSE; + keyc->curKeySyms.map = (KeySym *) NULL; + keyc->curKeySyms.mapWidth = 0; + keyc->curKeySyms.minKeyCode = pKeySyms->minKeyCode; + keyc->curKeySyms.maxKeyCode = pKeySyms->maxKeyCode; + keyc->modifierKeyMap = (KeyCode *) NULL; + keyc->state = 0; + keyc->prev_state = 0; + if (pModifiers) + memmove((char *) keyc->modifierMap, (char *) pModifiers, MAP_LENGTH); + else + bzero((char *) keyc->modifierMap, MAP_LENGTH); + bzero((char *) keyc->down, DOWN_LENGTH); + for (i = 0; i < 8; i++) + keyc->modifierKeyCount[i] = 0; + if (!SetKeySymsMap(&keyc->curKeySyms, pKeySyms) || !InitModMap(keyc)) { + free(keyc->curKeySyms.map); + free(keyc->modifierKeyMap); + free(keyc); + return FALSE; + } + dev->key = keyc; + return TRUE; +} + +_X_EXPORT Bool +InitButtonClassDeviceStruct(register DeviceIntPtr dev, int numButtons, + CARD8 *map) +{ + ButtonClassPtr butc; + + int i; + + butc = malloc(sizeof(ButtonClassRec)); + if (!butc) + return FALSE; + butc->numButtons = numButtons; + for (i = 1; i <= numButtons; i++) + butc->map[i] = map[i]; + butc->buttonsDown = 0; + butc->state = 0; + butc->motionMask = 0; + bzero((char *) butc->down, DOWN_LENGTH); + dev->button = butc; + return TRUE; +} + +_X_EXPORT Bool +InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, + ValuatorMotionProcPtr motionProc, + int numMotionEvents, int mode) +{ + int i; + + ValuatorClassPtr valc; + + valc = malloc(sizeof(ValuatorClassRec) + + numAxes * sizeof(AxisInfo) + + numAxes * sizeof(unsigned int)); + if (!valc) + return FALSE; + valc->GetMotionProc = motionProc; + valc->numMotionEvents = numMotionEvents; + valc->motionHintWindow = NullWindow; + valc->numAxes = numAxes; + valc->mode = mode; + valc->axes = (AxisInfoPtr) (valc + 1); + valc->axisVal = (int *) (valc->axes + numAxes); + for (i = 0; i < numAxes; i++) + valc->axisVal[i] = 0; + dev->valuator = valc; + return TRUE; +} + +_X_EXPORT Bool +InitFocusClassDeviceStruct(DeviceIntPtr dev) +{ + FocusClassPtr focc; + + focc = malloc(sizeof(FocusClassRec)); + if (!focc) + return FALSE; + focc->win = PointerRootWin; + focc->revert = None; + focc->time = currentTime; + focc->trace = (WindowPtr *) NULL; + focc->traceSize = 0; + focc->traceGood = 0; + dev->focus = focc; + return TRUE; +} + +_X_EXPORT Bool +InitKbdFeedbackClassDeviceStruct(DeviceIntPtr dev, BellProcPtr bellProc, + KbdCtrlProcPtr controlProc) +{ + KbdFeedbackPtr feedc; + + feedc = malloc(sizeof(KbdFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->BellProc = bellProc; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultKeyboardControl; + feedc->ctrl.id = 0; + if ((feedc->next = dev->kbdfeed) != 0) + feedc->ctrl.id = dev->kbdfeed->ctrl.id + 1; + dev->kbdfeed = feedc; + (*dev->kbdfeed->CtrlProc) (dev, &dev->kbdfeed->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc) +{ + PtrFeedbackPtr feedc; + + feedc = malloc(sizeof(PtrFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultPointerControl; + feedc->ctrl.id = 0; + if ((feedc->next = dev->ptrfeed)) + feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1; + dev->ptrfeed = feedc; + (*controlProc) (dev, &feedc->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, + ValuatorMotionProcPtr motionProc, + PtrCtrlProcPtr controlProc, int numMotionEvents) +{ + DeviceIntPtr dev = (DeviceIntPtr) device; + + return (InitButtonClassDeviceStruct(dev, numButtons, map) && + InitValuatorClassDeviceStruct(dev, 2, motionProc, + numMotionEvents, 0) && + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); +} + +_X_EXPORT Bool +InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms, + CARD8 pModifiers[], BellProcPtr bellProc, + KbdCtrlProcPtr controlProc) +{ + DeviceIntPtr dev = (DeviceIntPtr) device; + + return (InitKeyClassDeviceStruct(dev, pKeySyms, pModifiers) && + InitFocusClassDeviceStruct(dev) && + InitKbdFeedbackClassDeviceStruct(dev, bellProc, controlProc)); +} + +_X_EXPORT void +SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count, + ClientPtr client) +{ + int i; + + xEvent event; + + event.u.u.type = MappingNotify; + event.u.mappingNotify.request = request; + if (request == MappingKeyboard) { + event.u.mappingNotify.firstKeyCode = firstKeyCode; + event.u.mappingNotify.count = count; + } + + /* 0 is the server client */ + for (i = 1; i < currentMaxClients; i++) { + if (clients[i] && clients[i]->clientState == ClientStateRunning) { + event.u.u.sequenceNumber = clients[i]->sequence; + WriteEventsToClient(clients[i], 1, &event); + } + } +} + +/* + * n-squared algorithm. n < 255 and don't want to copy the whole thing and + * sort it to do the checking. How often is it called? Just being lazy? + */ +Bool +BadDeviceMap(register BYTE * buff, int length, unsigned low, unsigned high, + XID *errval) +{ + int i, j; + + for (i = 0; i < length; i++) + if (buff[i]) { /* only check non-zero elements */ + if ((low > buff[i]) || (high < buff[i])) { + *errval = buff[i]; + return TRUE; + } + for (j = i + 1; j < length; j++) + if (buff[i] == buff[j]) { + *errval = buff[i]; + return TRUE; + } + } + return FALSE; +} + +Bool +AllModifierKeysAreUp(dev, map1, per1, map2, per2) +DeviceIntPtr dev; + +CARD8 *map1, *map2; + +int per1, per2; +{ + int i, j, k; + + CARD8 *down = dev->key->down; + + for (i = 8; --i >= 0; map2 += per2) { + for (j = per1; --j >= 0; map1++) { + if (*map1 && BitIsOn(down, *map1)) { + for (k = per2; (--k >= 0) && (*map1 != map2[k]);); + if (k < 0) + return FALSE; + } + } + } + return TRUE; +} + +int +ProcSetModifierMapping(ClientPtr client) +{ + xSetModifierMappingReply rep; + + REQUEST(xSetModifierMappingReq); + KeyCode *inputMap; + + int inputMapLen; + + int i; + + DeviceIntPtr keybd = inputInfo.keyboard; + + KeyClassPtr keyc = keybd->key; + + REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); + + if (client->req_len != ((stuff->numKeyPerModifier << 1) + + (sizeof(xSetModifierMappingReq) >> 2))) + return BadLength; + + inputMapLen = 8 * stuff->numKeyPerModifier; + inputMap = (KeyCode *) &stuff[1]; + + /* + * Now enforce the restriction that "all of the non-zero keycodes must be + * in the range specified by min-keycode and max-keycode in the + * connection setup (else a Value error)" + */ + i = inputMapLen; + while (i--) { + if (inputMap[i] + && (inputMap[i] < keyc->curKeySyms.minKeyCode + || inputMap[i] > keyc->curKeySyms.maxKeyCode)) { + client->errorValue = inputMap[i]; + return BadValue; + } + } + + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = MappingSuccess; + + /* + * Now enforce the restriction that none of the old or new + * modifier keys may be down while we change the mapping, and + * that the DDX layer likes the choice. + */ + if (!AllModifierKeysAreUp(keybd, keyc->modifierKeyMap, + (int) keyc->maxKeysPerModifier, + inputMap, (int) stuff->numKeyPerModifier) + || + !AllModifierKeysAreUp(keybd, inputMap, (int) stuff->numKeyPerModifier, + keyc->modifierKeyMap, + (int) keyc->maxKeysPerModifier)) { + rep.success = MappingBusy; + } + else { + for (i = 0; i < inputMapLen; i++) { + if (inputMap[i] && !LegalModifier(inputMap[i], (DevicePtr) keybd)) { + rep.success = MappingFailed; + break; + } + } + } + + if (rep.success == MappingSuccess) { + KeyCode *map; + + /* + * Now build the keyboard's modifier bitmap from the + * list of keycodes. + */ + map = malloc(inputMapLen); + if (!map && inputMapLen) + return BadAlloc; + if (keyc->modifierKeyMap) + free(keyc->modifierKeyMap); + keyc->modifierKeyMap = map; + memmove((char *) map, (char *) inputMap, inputMapLen); + + keyc->maxKeysPerModifier = stuff->numKeyPerModifier; + for (i = 0; i < MAP_LENGTH; i++) + keyc->modifierMap[i] = 0; + for (i = 0; i < inputMapLen; i++) { + if (inputMap[i]) + keyc->modifierMap[inputMap[i]] |= + (1 << (((unsigned int) i) / keyc->maxKeysPerModifier)); + } + } + + if (rep.success == MappingSuccess) + SendMappingNotify(MappingModifier, 0, 0, client); + + WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); + + return (client->noClientException); +} + +int +ProcGetModifierMapping(ClientPtr client) +{ + xGetModifierMappingReply rep = {0}; + + KeyClassPtr keyc = inputInfo.keyboard->key; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.numKeyPerModifier = keyc->maxKeysPerModifier; + rep.sequenceNumber = client->sequence; + /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ + rep.length = keyc->maxKeysPerModifier << 1; + + WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); + + /* Use the (modified by DDX) map that SetModifierMapping passed in */ + (void) WriteToClient(client, (int) (keyc->maxKeysPerModifier << 3), + (char *) keyc->modifierKeyMap); + return client->noClientException; +} + +int +ProcChangeKeyboardMapping(ClientPtr client) +{ + REQUEST(xChangeKeyboardMappingReq); + unsigned len; + + KeySymsRec keysyms; + + KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + + REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); + + len = client->req_len - (sizeof(xChangeKeyboardMappingReq) >> 2); + if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) + return BadLength; + if ((stuff->firstKeyCode < curKeySyms->minKeyCode) || + (stuff->firstKeyCode > curKeySyms->maxKeyCode)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + if (((unsigned) (stuff->firstKeyCode + stuff->keyCodes - 1) > + curKeySyms->maxKeyCode) || (stuff->keySymsPerKeyCode == 0)) { + client->errorValue = stuff->keySymsPerKeyCode; + return BadValue; + } + keysyms.minKeyCode = stuff->firstKeyCode; + keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1; + keysyms.mapWidth = stuff->keySymsPerKeyCode; + keysyms.map = (KeySym *) & stuff[1]; + if (!SetKeySymsMap(curKeySyms, &keysyms)) + return BadAlloc; + SendMappingNotify(MappingKeyboard, stuff->firstKeyCode, stuff->keyCodes, + client); + return client->noClientException; + +} + +int +ProcSetPointerMapping(ClientPtr client) +{ + REQUEST(xSetPointerMappingReq); + BYTE *map; + + xSetPointerMappingReply rep; + + unsigned int i; + + DeviceIntPtr mouse = inputInfo.pointer; + + REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); + if (client->req_len != + (sizeof(xSetPointerMappingReq) + stuff->nElts + 3) >> 2) + return BadLength; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = MappingSuccess; + map = (BYTE *) & stuff[1]; + if (stuff->nElts != mouse->button->numButtons) { + client->errorValue = stuff->nElts; + return BadValue; + } + if (BadDeviceMap(&map[0], (int) stuff->nElts, 1, 255, &client->errorValue)) + return BadValue; + for (i = 0; i < stuff->nElts; i++) + if ((mouse->button->map[i + 1] != map[i]) && + BitIsOn(mouse->button->down, i + 1)) { + rep.success = MappingBusy; + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; + } + for (i = 0; i < stuff->nElts; i++) + mouse->button->map[i + 1] = map[i]; + SendMappingNotify(MappingPointer, 0, 0, client); + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; +} + +int +ProcGetKeyboardMapping(ClientPtr client) +{ + xGetKeyboardMappingReply rep = {0}; + + REQUEST(xGetKeyboardMappingReq); + KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + + REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); + + if ((stuff->firstKeyCode < curKeySyms->minKeyCode) || + (stuff->firstKeyCode > curKeySyms->maxKeyCode)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + if (stuff->firstKeyCode + stuff->count > + (unsigned) (curKeySyms->maxKeyCode + 1)) { + client->errorValue = stuff->count; + return BadValue; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.keySymsPerKeyCode = curKeySyms->mapWidth; + /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ + rep.length = (curKeySyms->mapWidth * stuff->count); + WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + WriteSwappedDataToClient(client, + curKeySyms->mapWidth * stuff->count * + sizeof(KeySym), + &curKeySyms-> + map[(stuff->firstKeyCode - + curKeySyms->minKeyCode) * + curKeySyms->mapWidth]); + + return client->noClientException; +} + +int +ProcGetPointerMapping(ClientPtr client) +{ + xGetPointerMappingReply rep; + + ButtonClassPtr butc = inputInfo.pointer->button; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.nElts = butc->numButtons; + rep.length = ((unsigned) rep.nElts + (4 - 1)) / 4; + WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); + (void) WriteToClient(client, (int) rep.nElts, (char *) &butc->map[1]); + return Success; +} + +void +NoteLedState(DeviceIntPtr keybd, int led, Bool on) +{ + KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl; + + if (on) + ctrl->leds |= ((Leds) 1 << (led - 1)); + else + ctrl->leds &= ~((Leds) 1 << (led - 1)); +} + +_X_EXPORT int +Ones(unsigned long mask) +{ /* HACKMEM 169 */ + unsigned long y; + + y = (mask >> 1) & 033333333333; + y = mask - y - ((y >> 1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +} + +int +ProcChangeKeyboardControl(ClientPtr client) +{ +#define DO_ALL (-1) + KeybdCtrl ctrl; + + DeviceIntPtr keybd = inputInfo.keyboard; + + XID *vlist; + + int t; + + int led = DO_ALL; + + int key = DO_ALL; + + BITS32 vmask, index2; + + int mask, i; + + REQUEST(xChangeKeyboardControlReq); + + REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); + vmask = stuff->mask; + if (client->req_len != + (sizeof(xChangeKeyboardControlReq) >> 2) + Ones(vmask)) + return BadLength; + vlist = (XID *) &stuff[1]; /* first word of values */ + ctrl = keybd->kbdfeed->ctrl; + while (vmask) { + index2 = (BITS32) lowbit(vmask); + vmask &= ~index2; + switch (index2) { + case KBKeyClickPercent: + t = (INT8) *vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.click; + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.click = t; + break; + case KBBellPercent: + t = (INT8) *vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.bell; + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.bell = t; + break; + case KBBellPitch: + t = (INT16) *vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.bell_pitch; + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_pitch = t; + break; + case KBBellDuration: + t = (INT16) *vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.bell_duration; + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_duration = t; + break; + case KBLed: + led = (CARD8) *vlist; + vlist++; + if (led < 1 || led > 32) { + client->errorValue = led; + return BadValue; + } + if (!(stuff->mask & KBLedMode)) + return BadMatch; + break; + case KBLedMode: + t = (CARD8) *vlist; + vlist++; + if (t == LedModeOff) { + if (led == DO_ALL) + ctrl.leds = 0x0; + else + ctrl.leds &= ~(((Leds) (1)) << (led - 1)); + } + else if (t == LedModeOn) { + if (led == DO_ALL) + ctrl.leds = ~0L; + else + ctrl.leds |= (((Leds) (1)) << (led - 1)); + } + else { + client->errorValue = t; + return BadValue; + } + break; + case KBKey: + key = (KeyCode) *vlist; + vlist++; + if ((KeyCode) key < inputInfo.keyboard->key->curKeySyms.minKeyCode + || (KeyCode) key > + inputInfo.keyboard->key->curKeySyms.maxKeyCode) { + client->errorValue = key; + return BadValue; + } + if (!(stuff->mask & KBAutoRepeatMode)) + return BadMatch; + break; + case KBAutoRepeatMode: + i = (key >> 3); + mask = (1 << (key & 7)); + t = (CARD8) *vlist; + vlist++; + if (t == AutoRepeatModeOff) { + if (key == DO_ALL) + ctrl.autoRepeat = FALSE; + else + ctrl.autoRepeats[i] &= ~mask; + } + else if (t == AutoRepeatModeOn) { + if (key == DO_ALL) + ctrl.autoRepeat = TRUE; + else + ctrl.autoRepeats[i] |= mask; + } + else if (t == AutoRepeatModeDefault) { + if (key == DO_ALL) + ctrl.autoRepeat = defaultKeyboardControl.autoRepeat; + else + ctrl.autoRepeats[i] = + (ctrl.autoRepeats[i] & ~mask) | + (defaultKeyboardControl.autoRepeats[i] & mask); + } + else { + client->errorValue = t; + return BadValue; + } + break; + default: + client->errorValue = stuff->mask; + return BadValue; + } + } + keybd->kbdfeed->ctrl = ctrl; + (*keybd->kbdfeed->CtrlProc) (keybd, &keybd->kbdfeed->ctrl); + return Success; +#undef DO_ALL +} + +int +ProcGetKeyboardControl(ClientPtr client) +{ + int i; + + KeybdCtrl *ctrl = &inputInfo.keyboard->kbdfeed->ctrl; + + xGetKeyboardControlReply rep; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.length = 5; + rep.sequenceNumber = client->sequence; + rep.globalAutoRepeat = ctrl->autoRepeat; + rep.keyClickPercent = ctrl->click; + rep.bellPercent = ctrl->bell; + rep.bellPitch = ctrl->bell_pitch; + rep.bellDuration = ctrl->bell_duration; + rep.ledMask = ctrl->leds; + for (i = 0; i < 32; i++) + rep.map[i] = ctrl->autoRepeats[i]; + WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep); + return Success; +} + +int +ProcBell(ClientPtr client) +{ + DeviceIntPtr keybd = inputInfo.keyboard; + + int base = keybd->kbdfeed->ctrl.bell; + + int newpercent; + + REQUEST(xBellReq); + REQUEST_SIZE_MATCH(xBellReq); + if (stuff->percent < -100 || stuff->percent > 100) { + client->errorValue = stuff->percent; + return BadValue; + } + newpercent = (base * stuff->percent) / 100; + if (stuff->percent < 0) + newpercent = base + newpercent; + else + newpercent = base - newpercent + stuff->percent; + (*keybd->kbdfeed->BellProc) (newpercent, keybd, + (pointer) &keybd->kbdfeed->ctrl, 0); + return Success; +} + +int +ProcChangePointerControl(ClientPtr client) +{ + DeviceIntPtr mouse = inputInfo.pointer; + + PtrCtrl ctrl; /* might get BadValue part way through */ + + REQUEST(xChangePointerControlReq); + + REQUEST_SIZE_MATCH(xChangePointerControlReq); + ctrl = mouse->ptrfeed->ctrl; + if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) { + client->errorValue = stuff->doAccel; + return (BadValue); + } + if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) { + client->errorValue = stuff->doThresh; + return (BadValue); + } + if (stuff->doAccel) { + if (stuff->accelNum == -1) + ctrl.num = defaultPointerControl.num; + else if (stuff->accelNum < 0) { + client->errorValue = stuff->accelNum; + return BadValue; + } + else + ctrl.num = stuff->accelNum; + if (stuff->accelDenum == -1) + ctrl.den = defaultPointerControl.den; + else if (stuff->accelDenum <= 0) { + client->errorValue = stuff->accelDenum; + return BadValue; + } + else + ctrl.den = stuff->accelDenum; + } + if (stuff->doThresh) { + if (stuff->threshold == -1) + ctrl.threshold = defaultPointerControl.threshold; + else if (stuff->threshold < 0) { + client->errorValue = stuff->threshold; + return BadValue; + } + else + ctrl.threshold = stuff->threshold; + } + mouse->ptrfeed->ctrl = ctrl; + (*mouse->ptrfeed->CtrlProc) (mouse, &mouse->ptrfeed->ctrl); + return Success; +} + +int +ProcGetPointerControl(ClientPtr client) +{ + PtrCtrl *ctrl = &inputInfo.pointer->ptrfeed->ctrl; + + xGetPointerControlReply rep; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.threshold = ctrl->threshold; + rep.accelNumerator = ctrl->num; + rep.accelDenominator = ctrl->den; + WriteReplyToClient(client, sizeof(xGenericReply), &rep); + return Success; +} + +void +MaybeStopHint(register DeviceIntPtr dev, ClientPtr client) +{ + GrabPtr grab = dev->grab; + + if ((grab && SameClient(grab, client) && + ((grab->eventMask & PointerMotionHintMask) || + (grab->ownerEvents && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask)))) || + (!grab && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask))) + dev->valuator->motionHintWindow = NullWindow; +} + +int +ProcGetMotionEvents(ClientPtr client) +{ + WindowPtr pWin; + + xTimecoord *coords = (xTimecoord *) NULL; + + xGetMotionEventsReply rep; + + int i, count, xmin, xmax, ymin, ymax; + + unsigned long nEvents; + + DeviceIntPtr mouse = inputInfo.pointer; + + TimeStamp start, stop; + + REQUEST(xGetMotionEventsReq); + + REQUEST_SIZE_MATCH(xGetMotionEventsReq); + pWin = SecurityLookupWindow(stuff->window, client, TRUE); + if (!pWin) + return BadWindow; + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + nEvents = 0; + start = ClientTimeToServerTime(stuff->start); + stop = ClientTimeToServerTime(stuff->stop); + if ((CompareTimeStamps(start, stop) != LATER) && + (CompareTimeStamps(start, currentTime) != LATER) && + mouse->valuator->numMotionEvents) { + if (CompareTimeStamps(stop, currentTime) == LATER) + stop = currentTime; + coords = (xTimecoord *) ALLOCATE_LOCAL(mouse->valuator->numMotionEvents + * sizeof(xTimecoord)); + if (!coords) + return BadAlloc; + count = (*mouse->valuator->GetMotionProc) (mouse, coords, + start.milliseconds, + stop.milliseconds, + pWin->drawable.pScreen); + xmin = pWin->drawable.x - wBorderWidth(pWin); + xmax = pWin->drawable.x + (int) pWin->drawable.width + + wBorderWidth(pWin); + ymin = pWin->drawable.y - wBorderWidth(pWin); + ymax = pWin->drawable.y + (int) pWin->drawable.height + + wBorderWidth(pWin); + for (i = 0; i < count; i++) + if ((xmin <= coords[i].x) && (coords[i].x < xmax) && + (ymin <= coords[i].y) && (coords[i].y < ymax)) { + coords[nEvents].time = coords[i].time; + coords[nEvents].x = coords[i].x - pWin->drawable.x; + coords[nEvents].y = coords[i].y - pWin->drawable.y; + nEvents++; + } + } + rep.length = nEvents * (sizeof(xTimecoord) >> 2); + rep.nEvents = nEvents; + WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); + if (nEvents) { + client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; + WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), + (char *) coords); + } + if (coords) + DEALLOCATE_LOCAL(coords); + return Success; +} + +int +ProcQueryKeymap(ClientPtr client) +{ + xQueryKeymapReply rep; + + int i; + + CARD8 *down = inputInfo.keyboard->key->down; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 2; + for (i = 0; i < 32; i++) + rep.map[i] = down[i]; + WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); + return Success; +} diff --git a/dix/dispatch.c b/dix/dispatch.c new file mode 100644 index 0000000..698ee87 --- /dev/null +++ b/dix/dispatch.c @@ -0,0 +1,3865 @@ +/************************************************************ + +Copyright 1987, 1989, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + + +#include "windowstr.h" +#include +#include "dixfontstr.h" +#include "gcstruct.h" +#include "selection.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "opaque.h" +#include "input.h" +#include "servermd.h" +#include "extnsionst.h" +#include "dixfont.h" +#include "dispatch.h" +#include "swaprep.h" +#include "swapreq.h" + +#define mskcnt ((MAXCLIENTS + 31) / 32) +#define BITMASK(i) (1U << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +extern xConnSetupPrefix connSetupPrefix; + +extern char *ConnectionInfo; + +_X_EXPORT Selection *CurrentSelections; + +_X_EXPORT int NumCurrentSelections; + +CallbackListPtr SelectionCallback = NULL; + +static ClientPtr grabClient; + +#define GrabNone 0 +#define GrabActive 1 +#define GrabKickout 2 +static int grabState = GrabNone; + +static long grabWaiters[mskcnt]; + +_X_EXPORT CallbackListPtr ServerGrabCallback = NULL; + +HWEventQueuePtr checkForInput[2]; + +extern int connBlockScreenStart; + +static void KillAllClients(void); + +static void DeleteClientFromAnySelections(ClientPtr client); + +static int nextFreeClientID; /* always MIN free client ID */ + +static int nClients; /* number of authorized clients */ + +_X_EXPORT CallbackListPtr ClientStateCallback; + +/* dispatchException & isItTimeToYield must be declared volatile since they + * are modified by signal handlers - otherwise optimizer may assume it doesn't + * need to actually check value in memory when used and may miss changes from + * signal handlers. + */ +_X_EXPORT volatile char dispatchException = 0; + +_X_EXPORT volatile char isItTimeToYield; + +/* Various of the DIX function interfaces were not designed to allow + * the client->errorValue to be set on BadValue and other errors. + * Rather than changing interfaces and breaking untold code we introduce + * a new global that dispatch can use. + */ +XID clientErrorValue; /* XXX this is a kludge */ + +#define SAME_SCREENS(a, b) (\ + (a.pScreen == b.pScreen)) + +_X_EXPORT void +SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1) +{ + checkForInput[0] = c0; + checkForInput[1] = c1; +} + +_X_EXPORT void +UpdateCurrentTime() +{ + TimeStamp systime; + + /* To avoid time running backwards, we must call GetTimeInMillis before + * calling ProcessInputEvents. + */ + systime.months = currentTime.months; + systime.milliseconds = GetTimeInMillis(); + if (systime.milliseconds < currentTime.milliseconds) + systime.months++; + if (*checkForInput[0] != *checkForInput[1]) + ProcessInputEvents(); + if (CompareTimeStamps(systime, currentTime) == LATER) + currentTime = systime; +} + +/* Like UpdateCurrentTime, but can't call ProcessInputEvents */ +_X_EXPORT void +UpdateCurrentTimeIf() +{ + TimeStamp systime; + + systime.months = currentTime.months; + systime.milliseconds = GetTimeInMillis(); + if (systime.milliseconds < currentTime.milliseconds) + systime.months++; + if (*checkForInput[0] == *checkForInput[1]) + currentTime = systime; +} + +void +InitSelections() +{ + if (CurrentSelections) + free(CurrentSelections); + CurrentSelections = (Selection *) NULL; + NumCurrentSelections = 0; +} + +void +FlushClientCaches(XID id) +{ + int i; + + ClientPtr client; + + client = clients[CLIENT_ID(id)]; + if (client == NullClient) + return; + for (i = 0; i < currentMaxClients; i++) { + client = clients[i]; + if (client != NullClient) { + if (client->lastDrawableID == id) { + client->lastDrawableID = WindowTable[0]->drawable.id; + client->lastDrawable = (DrawablePtr) WindowTable[0]; + } + else if (client->lastGCID == id) { + client->lastGCID = INVALID; + client->lastGC = (GCPtr) NULL; + } + } + } +} + +#ifdef SMART_SCHEDULE + +#undef SMART_DEBUG + +#define SMART_SCHEDULE_DEFAULT_INTERVAL 7 /* ms */ +#define SMART_SCHEDULE_MAX_SLICE 20 /* ms */ + +Bool SmartScheduleDisable = FALSE; + +long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL; + +long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL; + +long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE; + +long SmartScheduleTime; + +ClientPtr SmartLastClient; + +int SmartLastIndex[SMART_MAX_PRIORITY - SMART_MIN_PRIORITY + 1]; + +int SmartScheduleClient(int *clientReady, int nready); + +#ifdef SMART_DEBUG +long SmartLastPrint; +#endif + +void Dispatch(void); + +int +SmartScheduleClient(int *clientReady, int nready) +{ + ClientPtr pClient; + + int i; + + int client; + + int bestPrio, best = 0; + + int bestRobin, robin; + + long now = SmartScheduleTime; + + long idle; + + bestPrio = -0x7fffffff; + bestRobin = 0; + idle = 2 * SmartScheduleSlice; + for (i = 0; i < nready; i++) { + client = clientReady[i]; + pClient = clients[client]; + /* Praise clients which are idle */ + if ((now - pClient->smart_check_tick) >= idle) { + if (pClient->smart_priority < 0) + pClient->smart_priority++; + } + pClient->smart_check_tick = now; + + /* check priority to select best client */ + robin = + (pClient->index - + SmartLastIndex[pClient->smart_priority - + SMART_MIN_PRIORITY]) & 0xff; + if (pClient->smart_priority > bestPrio || + (pClient->smart_priority == bestPrio && robin > bestRobin)) { + bestPrio = pClient->smart_priority; + bestRobin = robin; + best = client; + } +#ifdef SMART_DEBUG + if ((now - SmartLastPrint) >= 5000) + fprintf(stderr, " %2d: %3d", client, pClient->smart_priority); +#endif + } +#ifdef SMART_DEBUG + if ((now - SmartLastPrint) >= 5000) { + fprintf(stderr, " use %2d\n", best); + SmartLastPrint = now; + } +#endif + pClient = clients[best]; + SmartLastIndex[bestPrio - SMART_MIN_PRIORITY] = pClient->index; + /* + * Set current client pointer + */ + if (SmartLastClient != pClient) { + pClient->smart_start_tick = now; + SmartLastClient = pClient; + } + /* + * Adjust slice + */ + if (nready == 1) { + /* + * If it's been a long time since another client + * has run, bump the slice up to get maximal + * performance from a single client + */ + if ((now - pClient->smart_start_tick) > 1000 && + SmartScheduleSlice < SmartScheduleMaxSlice) { + SmartScheduleSlice += SmartScheduleInterval; + } + } + else { + SmartScheduleSlice = SmartScheduleInterval; + } + return best; +} +#endif + +#define MAJOROP ((xReq *)client->requestBuffer)->reqType + +void +Dispatch(void) +{ + int *clientReady; /* array of request ready clients */ + + int result; + + ClientPtr client; + + int nready; + + HWEventQueuePtr *icheck = checkForInput; + +#ifdef SMART_SCHEDULE + long start_tick; +#endif + + nextFreeClientID = 1; + InitSelections(); + nClients = 0; + + clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients); + if (!clientReady) + return; + + while (!dispatchException) { + if (*icheck[0] != *icheck[1]) { + ProcessInputEvents(); + FlushIfCriticalOutputPending(); + } + + nready = WaitForSomething(clientReady); + +#ifdef SMART_SCHEDULE + if (nready && !SmartScheduleDisable) { + clientReady[0] = SmartScheduleClient(clientReady, nready); + nready = 1; + } +#endif + /***************** + * Handle events in round robin fashion, doing input between + * each round + *****************/ + + while (!dispatchException && (--nready >= 0)) { + client = clients[clientReady[nready]]; + if (!client) { + /* KillClient can cause this to happen */ + continue; + } + /* GrabServer activation can cause this to be true */ + if (grabState == GrabKickout) { + grabState = GrabActive; + break; + } + isItTimeToYield = FALSE; + + requestingClient = client; +#ifdef SMART_SCHEDULE + start_tick = SmartScheduleTime; +#endif + while (!isItTimeToYield) { + if (*icheck[0] != *icheck[1]) { + ProcessInputEvents(); + FlushIfCriticalOutputPending(); + } +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable && + (SmartScheduleTime - start_tick) >= SmartScheduleSlice) { + /* Penalize clients which consume ticks */ + if (client->smart_priority > SMART_MIN_PRIORITY) + client->smart_priority--; + break; + } +#endif + /* now, finally, deal with client requests */ + + result = ReadRequestFromClient(client); + if (result <= 0) { + if (result < 0) + CloseDownClient(client); + break; + } + + client->sequence++; +#ifdef DEBUG + if (client->requestLogIndex == MAX_REQUEST_LOG) + client->requestLogIndex = 0; + client->requestLog[client->requestLogIndex] = MAJOROP; + client->requestLogIndex++; +#endif + if (result > (maxBigRequestSize << 2)) + result = BadLength; + else + result = (*client->requestVector[MAJOROP]) (client); + + if (result != Success) { + if (client->noClientException != Success) + CloseDownClient(client); + else + SendErrorToClient(client, MAJOROP, + MinorOpcodeOfRequest(client), + client->errorValue, result); + break; + } + } + FlushAllOutput(); +#ifdef SMART_SCHEDULE + client = clients[clientReady[nready]]; + if (client) + client->smart_stop_tick = SmartScheduleTime; +#endif + requestingClient = NULL; + } + dispatchException &= ~DE_PRIORITYCHANGE; + } + KillAllClients(); + DEALLOCATE_LOCAL(clientReady); + dispatchException &= ~DE_RESET; + ResetOsBuffers(); +} + +#undef MAJOROP + +_X_EXPORT int +ProcBadRequest(ClientPtr client) +{ + return (BadRequest); +} + +int +ProcCreateWindow(ClientPtr client) +{ + WindowPtr pParent, pWin; + + REQUEST(xCreateWindowReq); + int result; + + int len; + + REQUEST_AT_LEAST_SIZE(xCreateWindowReq); + + LEGAL_NEW_RESOURCE(stuff->wid, client); + if (!(pParent = (WindowPtr) SecurityLookupWindow(stuff->parent, client, + SecurityWriteAccess))) + return BadWindow; + len = client->req_len - (sizeof(xCreateWindowReq) >> 2); + if (Ones(stuff->mask) != len) + return BadLength; + if (!stuff->width || !stuff->height) { + client->errorValue = 0; + return BadValue; + } + pWin = CreateWindow(stuff->wid, pParent, stuff->x, + stuff->y, stuff->width, stuff->height, + stuff->borderWidth, stuff->class, + stuff->mask, (XID *) &stuff[1], + (int) stuff->depth, client, stuff->visual, &result); + if (pWin) { + Mask mask = pWin->eventMask; + + pWin->eventMask = 0; /* subterfuge in case AddResource fails */ + if (!AddResource(stuff->wid, RT_WINDOW, (pointer) pWin)) + return BadAlloc; + pWin->eventMask = mask; + } + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); +} + +int +ProcChangeWindowAttributes(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xChangeWindowAttributesReq); + int result; + + int len; + + REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess); + if (!pWin) + return (BadWindow); + len = client->req_len - (sizeof(xChangeWindowAttributesReq) >> 2); + if (len != Ones(stuff->valueMask)) + return BadLength; + result = ChangeWindowAttributes(pWin, + stuff->valueMask, + (XID *) &stuff[1], client); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); +} + +int +ProcGetWindowAttributes(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + xGetWindowAttributesReply wa = {0}; + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + GetWindowAttributes(pWin, client, &wa); + WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa); + return (client->noClientException); +} + +int +ProcDestroyWindow(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityDestroyAccess); + if (!pWin) + return (BadWindow); + if (pWin->parent) + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); +} + +int +ProcDestroySubwindows(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityDestroyAccess); + if (!pWin) + return (BadWindow); + DestroySubwindows(pWin, client); + return (client->noClientException); +} + +int +ProcChangeSaveSet(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xChangeSaveSetReq); + int result; + + REQUEST_SIZE_MATCH(xChangeSaveSetReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) + return BadMatch; + if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete)) { + result = AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); + } + else { + client->errorValue = stuff->mode; + return (BadValue); + } +} + +int +ProcReparentWindow(register ClientPtr client) +{ + WindowPtr pWin, pParent; + + REQUEST(xReparentWindowReq); + int result; + + REQUEST_SIZE_MATCH(xReparentWindowReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess); + if (!pWin) + return (BadWindow); + pParent = (WindowPtr) SecurityLookupWindow(stuff->parent, client, + SecurityWriteAccess); + if (!pParent) + return (BadWindow); + if (SAME_SCREENS(pWin->drawable, pParent->drawable)) { + if ((pWin->backgroundState == ParentRelative) && + (pParent->drawable.depth != pWin->drawable.depth)) + return BadMatch; + if ((pWin->drawable.class != InputOnly) && + (pParent->drawable.class == InputOnly)) + return BadMatch; + result = ReparentWindow(pWin, pParent, + (short) stuff->x, (short) stuff->y, client); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); + } + else + return (BadMatch); +} + +int +ProcMapWindow(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + MapWindow(pWin, client); + /* update cache to say it is mapped */ + return (client->noClientException); +} + +int +ProcMapSubwindows(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + MapSubwindows(pWin, client); + /* update cache to say it is mapped */ + return (client->noClientException); +} + +int +ProcUnmapWindow(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + UnmapWindow(pWin, FALSE); + /* update cache to say it is mapped */ + return (client->noClientException); +} + +int +ProcUnmapSubwindows(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + UnmapSubwindows(pWin); + return (client->noClientException); +} + +int +ProcConfigureWindow(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xConfigureWindowReq); + int result; + + int len; + + REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess); + if (!pWin) + return (BadWindow); + len = client->req_len - (sizeof(xConfigureWindowReq) >> 2); + if (Ones((Mask) stuff->mask) != len) + return BadLength; + result = ConfigureWindow(pWin, (Mask) stuff->mask, (XID *) &stuff[1], + client); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); +} + +int +ProcCirculateWindow(register ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xCirculateWindowReq); + + REQUEST_SIZE_MATCH(xCirculateWindowReq); + if ((stuff->direction != RaiseLowest) && (stuff->direction != LowerHighest)) { + client->errorValue = stuff->direction; + return BadValue; + } + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess); + if (!pWin) + return (BadWindow); + CirculateWindow(pWin, (int) stuff->direction, client); + return (client->noClientException); +} + +int +GetGeometry(register ClientPtr client, xGetGeometryReply * rep) +{ + DrawablePtr pDraw; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + SECURITY_VERIFY_GEOMETRABLE(pDraw, stuff->id, client, SecurityReadAccess); + rep->type = X_Reply; + rep->length = 0; + rep->sequenceNumber = client->sequence; + rep->root = WindowTable[pDraw->pScreen->myNum]->drawable.id; + rep->depth = pDraw->depth; + rep->width = pDraw->width; + rep->height = pDraw->height; + + /* XXX - Because the pixmap-implementation of the multibuffer extension + * may have the buffer-id's drawable resource value be a pointer + * to the buffer's window instead of the buffer itself + * (this happens if the buffer is the displayed buffer), + * we also have to check that the id matches before we can + * truly say that it is a DRAWABLE_WINDOW. + */ + + if ((pDraw->type == UNDRAWABLE_WINDOW) || + ((pDraw->type == DRAWABLE_WINDOW) && (stuff->id == pDraw->id))) { + WindowPtr pWin = (WindowPtr) pDraw; + + rep->x = pWin->origin.x - wBorderWidth(pWin); + rep->y = pWin->origin.y - wBorderWidth(pWin); + rep->borderWidth = pWin->borderWidth; + } + else { /* DRAWABLE_PIXMAP or DRAWABLE_BUFFER */ + + rep->x = rep->y = rep->borderWidth = 0; + } + + return Success; +} + +int +ProcGetGeometry(register ClientPtr client) +{ + xGetGeometryReply rep = {0}; + + int status; + + if ((status = GetGeometry(client, &rep)) != Success) + return status; + + WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); + return (client->noClientException); +} + +int +ProcQueryTree(register ClientPtr client) +{ + xQueryTreeReply reply; + + int numChildren = 0; + + WindowPtr pChild, pWin, pHead; + + Window *childIDs = (Window *) NULL; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + reply.type = X_Reply; + reply.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id; + reply.sequenceNumber = client->sequence; + if (pWin->parent) + reply.parent = pWin->parent->drawable.id; + else + reply.parent = (Window) None; + pHead = RealChildHead(pWin); + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + numChildren++; + if (numChildren) { + int curChild = 0; + + childIDs = (Window *) ALLOCATE_LOCAL(numChildren * sizeof(Window)); + if (!childIDs) + return BadAlloc; + for (pChild = pWin->lastChild; pChild != pHead; + pChild = pChild->prevSib) + childIDs[curChild++] = pChild->drawable.id; + } + + reply.nChildren = numChildren; + reply.length = (numChildren * sizeof(Window)) >> 2; + + WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply); + if (numChildren) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, numChildren * sizeof(Window), + childIDs); + DEALLOCATE_LOCAL(childIDs); + } + + return (client->noClientException); +} + +int +ProcInternAtom(register ClientPtr client) +{ + Atom atom; + + char *tchar; + + REQUEST(xInternAtomReq); + + REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes); + if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse)) { + client->errorValue = stuff->onlyIfExists; + return (BadValue); + } + tchar = (char *) &stuff[1]; + atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists); + if (atom != BAD_RESOURCE) { + xInternAtomReply reply = {0}; + + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.atom = atom; + WriteReplyToClient(client, sizeof(xInternAtomReply), &reply); + return (client->noClientException); + } + else + return (BadAlloc); +} + +int +ProcGetAtomName(register ClientPtr client) +{ + char *str; + + xGetAtomNameReply reply; + + int len; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + if ((str = NameForAtom(stuff->id))) { + len = strlen(str); + reply.type = X_Reply; + reply.length = (len + 3) >> 2; + reply.sequenceNumber = client->sequence; + reply.nameLength = len; + WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply); + (void) WriteToClient(client, len, str); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadAtom); + } +} + + +int +ProcSetSelectionOwner(register ClientPtr client) +{ + WindowPtr pWin; + + TimeStamp time; + + REQUEST(xSetSelectionOwnerReq); + + REQUEST_SIZE_MATCH(xSetSelectionOwnerReq); + UpdateCurrentTime(); + time = ClientTimeToServerTime(stuff->time); + + /* If the client's time stamp is in the future relative to the server's + time stamp, do not set the selection, just return success. */ + if (CompareTimeStamps(time, currentTime) == LATER) + return Success; + if (stuff->window != None) { + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + } + else + pWin = (WindowPtr) None; + if (ValidAtom(stuff->selection)) { + int i = 0; + + /* + * First, see if the selection is already set... + */ + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->selection) + i++; + if (i < NumCurrentSelections) { + xEvent event; + + /* If the timestamp in client's request is in the past relative + to the time stamp indicating the last time the owner of the + selection was set, do not set the selection, just return + success. */ + if (CompareTimeStamps(time, CurrentSelections[i].lastTimeChanged) + == EARLIER) + return Success; + if (CurrentSelections[i].client && + (!pWin || (CurrentSelections[i].client != client))) { + event.u.u.type = SelectionClear; + event.u.selectionClear.time = time.milliseconds; + event.u.selectionClear.window = CurrentSelections[i].window; + event.u.selectionClear.atom = CurrentSelections[i].selection; + (void) TryClientEvents(CurrentSelections[i].client, &event, 1, + NoEventMask, + NoEventMask /* CantBeFiltered */ , + NullGrab); + } + } + else { + /* + * It doesn't exist, so add it... + */ + Selection *newsels; + + if (i == 0) + newsels = malloc(sizeof(Selection)); + else + newsels = (Selection *) realloc(CurrentSelections, + (NumCurrentSelections + + 1) * sizeof(Selection)); + if (!newsels) + return BadAlloc; + NumCurrentSelections++; + CurrentSelections = newsels; + CurrentSelections[i].selection = stuff->selection; + } + CurrentSelections[i].lastTimeChanged = time; + CurrentSelections[i].window = stuff->window; + CurrentSelections[i].pWin = pWin; + CurrentSelections[i].client = (pWin ? client : NullClient); + if (SelectionCallback) { + SelectionInfoRec info; + + info.selection = &CurrentSelections[i]; + info.kind = SelectionSetOwner; + CallCallbacks(&SelectionCallback, &info); + } + return (client->noClientException); + } + else { + client->errorValue = stuff->selection; + return (BadAtom); + } +} + +int +ProcGetSelectionOwner(register ClientPtr client) +{ + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + if (ValidAtom(stuff->id)) { + int i; + + xGetSelectionOwnerReply reply; + + i = 0; + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->id) + i++; + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + if (i < NumCurrentSelections) + reply.owner = CurrentSelections[i].window; + else + reply.owner = None; + WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadAtom); + } +} + +int +ProcConvertSelection(register ClientPtr client) +{ + Bool paramsOkay; + + xEvent event; + + WindowPtr pWin; + + REQUEST(xConvertSelectionReq); + + REQUEST_SIZE_MATCH(xConvertSelectionReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->requestor, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + + paramsOkay = (ValidAtom(stuff->selection) && ValidAtom(stuff->target)); + if (stuff->property != None) + paramsOkay &= ValidAtom(stuff->property); + if (paramsOkay) { + int i; + + i = 0; + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->selection) + i++; + if ((i < NumCurrentSelections) && (CurrentSelections[i].window != None) + ) { + event.u.u.type = SelectionRequest; + event.u.selectionRequest.time = stuff->time; + event.u.selectionRequest.owner = CurrentSelections[i].window; + event.u.selectionRequest.requestor = stuff->requestor; + event.u.selectionRequest.selection = stuff->selection; + event.u.selectionRequest.target = stuff->target; + event.u.selectionRequest.property = stuff->property; + if (TryClientEvents + (CurrentSelections[i].client, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */ , NullGrab)) + return (client->noClientException); + } + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = stuff->time; + event.u.selectionNotify.requestor = stuff->requestor; + event.u.selectionNotify.selection = stuff->selection; + event.u.selectionNotify.target = stuff->target; + event.u.selectionNotify.property = None; + (void) TryClientEvents(client, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */ , NullGrab); + return (client->noClientException); + } + else { + client->errorValue = stuff->property; + return (BadAtom); + } +} + +int +ProcGrabServer(register ClientPtr client) +{ + REQUEST_SIZE_MATCH(xReq); + if (grabState != GrabNone && client != grabClient) { + ResetCurrentRequest(client); + client->sequence--; + BITSET(grabWaiters, client->index); + IgnoreClient(client); + return (client->noClientException); + } + OnlyListenToOneClient(client); + grabState = GrabKickout; + grabClient = client; + + if (ServerGrabCallback) { + ServerGrabInfoRec grabinfo; + + grabinfo.client = client; + grabinfo.grabstate = SERVER_GRABBED; + CallCallbacks(&ServerGrabCallback, (pointer) &grabinfo); + } + + return (client->noClientException); +} + +static void +UngrabServer(ClientPtr client) +{ + int i; + + grabState = GrabNone; + ListenToAllClients(); + for (i = mskcnt; --i >= 0 && !grabWaiters[i];); + if (i >= 0) { + i <<= 5; + while (!GETBIT(grabWaiters, i)) + i++; + BITCLEAR(grabWaiters, i); + AttendClient(clients[i]); + } + + if (ServerGrabCallback) { + ServerGrabInfoRec grabinfo; + + grabinfo.client = client; + grabinfo.grabstate = SERVER_UNGRABBED; + CallCallbacks(&ServerGrabCallback, (pointer) &grabinfo); + } +} + +int +ProcUngrabServer(register ClientPtr client) +{ + REQUEST_SIZE_MATCH(xReq); + UngrabServer(client); + return (client->noClientException); +} + +int +ProcTranslateCoords(register ClientPtr client) +{ + REQUEST(xTranslateCoordsReq); + + WindowPtr pWin, pDst; + + xTranslateCoordsReply rep; + + REQUEST_SIZE_MATCH(xTranslateCoordsReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->srcWid, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + pDst = (WindowPtr) SecurityLookupWindow(stuff->dstWid, client, + SecurityReadAccess); + if (!pDst) + return (BadWindow); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (!SAME_SCREENS(pWin->drawable, pDst->drawable)) { + rep.sameScreen = xFalse; + rep.child = None; + rep.dstX = rep.dstY = 0; + } + else { + INT16 x, y; + + rep.sameScreen = xTrue; + rep.child = None; + /* computing absolute coordinates -- adjust to destination later */ + x = pWin->drawable.x + stuff->srcX; + y = pWin->drawable.y + stuff->srcY; + pWin = pDst->firstChild; + while (pWin) { + BoxRec box; + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth(pWin)) && + (x < pWin->drawable.x + (int) pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth(pWin)) && + (y < pWin->drawable.y + (int) pWin->drawable.height + + wBorderWidth(pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || + POINT_IN_REGION( + &pWin->borderSize, x, y, &box)) + + && (!wInputShape(pWin) || + POINT_IN_REGION( + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) + ) { + rep.child = pWin->drawable.id; + pWin = (WindowPtr) NULL; + } + else + pWin = pWin->nextSib; + } + /* adjust to destination coordinates */ + rep.dstX = x - pDst->drawable.x; + rep.dstY = y - pDst->drawable.y; + } + WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); + return (client->noClientException); +} + +int +ProcOpenFont(register ClientPtr client) +{ + int err; + + REQUEST(xOpenFontReq); + + REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes); + client->errorValue = stuff->fid; + LEGAL_NEW_RESOURCE(stuff->fid, client); + err = OpenFont(client, stuff->fid, (Mask) 0, + stuff->nbytes, (char *) &stuff[1]); + if (err == Success) { + return (client->noClientException); + } + else + return err; +} + +int +ProcCloseFont(register ClientPtr client) +{ + FontPtr pFont; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pFont = (FontPtr) SecurityLookupIDByType(client, stuff->id, RT_FONT, + SecurityDestroyAccess); + if (pFont != (FontPtr) NULL) { /* id was valid */ + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadFont); + } +} + +int +ProcQueryFont(register ClientPtr client) +{ + xQueryFontReply *reply; + + FontPtr pFont; + + GC *pGC; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + client->errorValue = stuff->id; /* EITHER font or gc */ + pFont = (FontPtr) SecurityLookupIDByType(client, stuff->id, RT_FONT, + SecurityReadAccess); + if (!pFont) { + /* can't use VERIFY_GC because it might return BadGC */ + pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC, + SecurityReadAccess); + if (!pGC) { + client->errorValue = stuff->id; + return (BadFont); /* procotol spec says only error is BadFont */ + } + pFont = pGC->font; + } + + { + xCharInfo *pmax = FONTINKMAX(pFont); + + xCharInfo *pmin = FONTINKMIN(pFont); + + int nprotoxcistructs; + + int rlength; + + nprotoxcistructs = (pmax->rightSideBearing == pmin->rightSideBearing && + pmax->leftSideBearing == pmin->leftSideBearing && + pmax->descent == pmin->descent && + pmax->ascent == pmin->ascent && + pmax->characterWidth == pmin->characterWidth) ? + 0 : N2dChars(pFont); + + rlength = sizeof(xQueryFontReply) + + FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) + + nprotoxcistructs * sizeof(xCharInfo); + reply = (xQueryFontReply *) ALLOCATE_LOCAL(rlength); + if (!reply) { + return (BadAlloc); + } + + reply->type = X_Reply; + reply->length = (rlength - sizeof(xGenericReply)) >> 2; + reply->sequenceNumber = client->sequence; + QueryFont(pFont, reply, nprotoxcistructs); + + WriteReplyToClient(client, rlength, reply); + DEALLOCATE_LOCAL(reply); + return (client->noClientException); + } +} + +int +ProcQueryTextExtents(register ClientPtr client) +{ + REQUEST(xQueryTextExtentsReq); + xQueryTextExtentsReply reply; + + FontPtr pFont; + + GC *pGC; + + ExtentInfoRec info; + + unsigned long length; + + REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq); + + pFont = (FontPtr) SecurityLookupIDByType(client, stuff->fid, RT_FONT, + SecurityReadAccess); + if (!pFont) { + pGC = (GC *) SecurityLookupIDByType(client, stuff->fid, RT_GC, + SecurityReadAccess); + if (!pGC) { + client->errorValue = stuff->fid; + return (BadFont); + } + pFont = pGC->font; + } + length = client->req_len - (sizeof(xQueryTextExtentsReq) >> 2); + length = length << 1; + if (stuff->oddLength) { + if (length == 0) + return (BadLength); + length--; + } + if (!QueryTextExtents(pFont, length, (unsigned char *) &stuff[1], &info)) + return (BadAlloc); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.drawDirection = info.drawDirection; + reply.fontAscent = info.fontAscent; + reply.fontDescent = info.fontDescent; + reply.overallAscent = info.overallAscent; + reply.overallDescent = info.overallDescent; + reply.overallWidth = info.overallWidth; + reply.overallLeft = info.overallLeft; + reply.overallRight = info.overallRight; + WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply); + return (client->noClientException); +} + +int +ProcListFonts(register ClientPtr client) +{ + REQUEST(xListFontsReq); + + REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes); + + return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes, + stuff->maxNames); +} + +int +ProcListFontsWithInfo(register ClientPtr client) +{ + REQUEST(xListFontsWithInfoReq); + + REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes); + + return StartListFontsWithInfo(client, stuff->nbytes, + (unsigned char *) &stuff[1], stuff->maxNames); +} + +/** + * + * \param value must conform to DeleteType + */ +int +dixDestroyPixmap(pointer value, XID pid) +{ + PixmapPtr pPixmap = (PixmapPtr) value; + + return (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap); +} + +int +ProcCreatePixmap(register ClientPtr client) +{ + PixmapPtr pMap; + + DrawablePtr pDraw; + + REQUEST(xCreatePixmapReq); + DepthPtr pDepth; + + int i; + + REQUEST_SIZE_MATCH(xCreatePixmapReq); + client->errorValue = stuff->pid; + LEGAL_NEW_RESOURCE(stuff->pid, client); + SECURITY_VERIFY_GEOMETRABLE(pDraw, stuff->drawable, client, + SecurityReadAccess); + if (!stuff->width || !stuff->height) { + client->errorValue = 0; + return BadValue; + } + if (stuff->width > 32767 || stuff->height > 32767) { + /* It is allowed to try and allocate a pixmap which is larger than + * 32767 in either dimension. However, all of the framebuffer code + * is buggy and does not reliably draw to such big pixmaps, basically + * because the Region data structure operates with signed shorts + * for the rectangles in it. + * + * Furthermore, several places in the X server computes the + * size in bytes of the pixmap and tries to store it in an + * integer. This integer can overflow and cause the allocated size + * to be much smaller. + * + * So, such big pixmaps are rejected here with a BadAlloc + */ + return BadAlloc; + } + if (stuff->depth != 1) { + pDepth = pDraw->pScreen->allowedDepths; + for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } + CreatePmap: + pMap = (PixmapPtr) (*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, stuff->width, stuff->height, stuff->depth); + if (pMap) { + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = stuff->pid; + if (AddResource(stuff->pid, RT_PIXMAP, (pointer) pMap)) + return (client->noClientException); + } + return (BadAlloc); +} + +int +ProcFreePixmap(register ClientPtr client) +{ + PixmapPtr pMap; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pMap = (PixmapPtr) SecurityLookupIDByType(client, stuff->id, RT_PIXMAP, + SecurityDestroyAccess); + if (pMap) { + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadPixmap); + } +} + +int +ProcCreateGC(register ClientPtr client) +{ + int error; + + GC *pGC; + + DrawablePtr pDraw; + + unsigned len; + + REQUEST(xCreateGCReq); + + REQUEST_AT_LEAST_SIZE(xCreateGCReq); + client->errorValue = stuff->gc; + LEGAL_NEW_RESOURCE(stuff->gc, client); + SECURITY_VERIFY_DRAWABLE(pDraw, stuff->drawable, client, + SecurityReadAccess); + len = client->req_len - (sizeof(xCreateGCReq) >> 2); + if (len != Ones(stuff->mask)) + return BadLength; + pGC = (GC *) CreateGC(pDraw, stuff->mask, (XID *) &stuff[1], &error); + if (error != Success) + return error; + if (!AddResource(stuff->gc, RT_GC, (pointer) pGC)) + return (BadAlloc); + return (client->noClientException); +} + +int +ProcChangeGC(register ClientPtr client) +{ + GC *pGC; + + REQUEST(xChangeGCReq); + int result; + + unsigned len; + + REQUEST_AT_LEAST_SIZE(xChangeGCReq); + SECURITY_VERIFY_GC(pGC, stuff->gc, client, SecurityWriteAccess); + len = client->req_len - (sizeof(xChangeGCReq) >> 2); + if (len != Ones(stuff->mask)) + return BadLength; + + result = dixChangeGC(client, pGC, stuff->mask, (CARD32 *) &stuff[1], 0); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (result); + } +} + +int +ProcCopyGC(register ClientPtr client) +{ + GC *dstGC; + + GC *pGC; + + int result; + + REQUEST(xCopyGCReq); + + REQUEST_SIZE_MATCH(xCopyGCReq); + SECURITY_VERIFY_GC(pGC, stuff->srcGC, client, SecurityReadAccess); + SECURITY_VERIFY_GC(dstGC, stuff->dstGC, client, SecurityWriteAccess); + if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth)) + return (BadMatch); + result = CopyGC(pGC, dstGC, stuff->mask); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (result); + } +} + +int +ProcSetDashes(register ClientPtr client) +{ + GC *pGC; + + int result; + + REQUEST(xSetDashesReq); + + REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes); + if (stuff->nDashes == 0) { + client->errorValue = 0; + return BadValue; + } + + SECURITY_VERIFY_GC(pGC, stuff->gc, client, SecurityWriteAccess); + + result = SetDashes(pGC, stuff->dashOffset, stuff->nDashes, + (unsigned char *) &stuff[1]); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (result); + } +} + +int +ProcSetClipRectangles(register ClientPtr client) +{ + int nr; + + int result; + + GC *pGC; + + REQUEST(xSetClipRectanglesReq); + + REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq); + if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) && + (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) { + client->errorValue = stuff->ordering; + return BadValue; + } + SECURITY_VERIFY_GC(pGC, stuff->gc, client, SecurityWriteAccess); + + nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq); + if (nr & 4) + return (BadLength); + nr >>= 3; + result = SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin, + nr, (xRectangle *) &stuff[1], (int) stuff->ordering); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); +} + +int +ProcFreeGC(register ClientPtr client) +{ + GC *pGC; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + SECURITY_VERIFY_GC(pGC, stuff->id, client, SecurityDestroyAccess); + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); +} + +int +ProcClearToBackground(register ClientPtr client) +{ + REQUEST(xClearAreaReq); + WindowPtr pWin; + + REQUEST_SIZE_MATCH(xClearAreaReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityWriteAccess); + if (!pWin) + return (BadWindow); + if (pWin->drawable.class == InputOnly) { + client->errorValue = stuff->window; + return (BadMatch); + } + if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse)) { + client->errorValue = stuff->exposures; + return (BadValue); + } + (*pWin->drawable.pScreen->ClearToBackground) (pWin, stuff->x, stuff->y, + stuff->width, stuff->height, + (Bool) stuff->exposures); + return (client->noClientException); +} + +int +ProcCopyArea(register ClientPtr client) +{ + DrawablePtr pDst; + + DrawablePtr pSrc; + + GC *pGC; + + REQUEST(xCopyAreaReq); + RegionPtr pRgn; + + REQUEST_SIZE_MATCH(xCopyAreaReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, pGC, client); + if (stuff->dstDrawable != stuff->srcDrawable) { + SECURITY_VERIFY_DRAWABLE(pSrc, stuff->srcDrawable, client, + SecurityReadAccess); + if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth)) { + client->errorValue = stuff->dstDrawable; + return (BadMatch); + } + } + else + pSrc = pDst; + + SET_DBE_SRCBUF(pSrc, stuff->srcDrawable); + + pRgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, stuff->srcX, stuff->srcY, + stuff->width, stuff->height, + stuff->dstX, stuff->dstY); + if (pGC->graphicsExposures) { + (*pDst->pScreen->SendGraphicsExpose) + (client, pRgn, stuff->dstDrawable, X_CopyArea, 0); + if (pRgn) + REGION_DESTROY(pRgn); + } + + return (client->noClientException); +} + +int +ProcCopyPlane(register ClientPtr client) +{ + DrawablePtr psrcDraw, pdstDraw; + + GC *pGC; + + REQUEST(xCopyPlaneReq); + RegionPtr pRgn; + + REQUEST_SIZE_MATCH(xCopyPlaneReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, pGC, client); + if (stuff->dstDrawable != stuff->srcDrawable) { + SECURITY_VERIFY_DRAWABLE(psrcDraw, stuff->srcDrawable, client, + SecurityReadAccess); + if (pdstDraw->pScreen != psrcDraw->pScreen) { + client->errorValue = stuff->dstDrawable; + return (BadMatch); + } + } + else + psrcDraw = pdstDraw; + + SET_DBE_SRCBUF(psrcDraw, stuff->srcDrawable); + + /* Check to see if stuff->bitPlane has exactly ONE good bit set */ + if (stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) || + (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) { + client->errorValue = stuff->bitPlane; + return (BadValue); + } + + pRgn = + (*pGC->ops->CopyPlane) (psrcDraw, pdstDraw, pGC, stuff->srcX, + stuff->srcY, stuff->width, stuff->height, + stuff->dstX, stuff->dstY, stuff->bitPlane); + if (pGC->graphicsExposures) { + (*pdstDraw->pScreen->SendGraphicsExpose) + (client, pRgn, stuff->dstDrawable, X_CopyPlane, 0); + if (pRgn) + REGION_DESTROY(pRgn); + } + return (client->noClientException); +} + +int +ProcPolyPoint(register ClientPtr client) +{ + int npoint; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyPointReq); + + REQUEST_AT_LEAST_SIZE(xPolyPointReq); + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) { + client->errorValue = stuff->coordMode; + return BadValue; + } + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + npoint = ((client->req_len << 2) - sizeof(xPolyPointReq)) >> 2; + if (npoint) + (*pGC->ops->PolyPoint) (pDraw, pGC, stuff->coordMode, npoint, + (xPoint *) & stuff[1]); + return (client->noClientException); +} + +int +ProcPolyLine(register ClientPtr client) +{ + int npoint; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyLineReq); + + REQUEST_AT_LEAST_SIZE(xPolyLineReq); + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) { + client->errorValue = stuff->coordMode; + return BadValue; + } + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + npoint = ((client->req_len << 2) - sizeof(xPolyLineReq)) >> 2; + if (npoint > 1) + (*pGC->ops->Polylines) (pDraw, pGC, stuff->coordMode, npoint, + (DDXPointPtr) & stuff[1]); + return (client->noClientException); +} + +int +ProcPolySegment(register ClientPtr client) +{ + int nsegs; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolySegmentReq); + + REQUEST_AT_LEAST_SIZE(xPolySegmentReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq); + if (nsegs & 4) + return (BadLength); + nsegs >>= 3; + if (nsegs) + (*pGC->ops->PolySegment) (pDraw, pGC, nsegs, (xSegment *) & stuff[1]); + return (client->noClientException); +} + +int +ProcPolyRectangle(register ClientPtr client) +{ + int nrects; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyRectangleReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq); + if (nrects & 4) + return (BadLength); + nrects >>= 3; + if (nrects) + (*pGC->ops->PolyRectangle) (pDraw, pGC, + nrects, (xRectangle *) &stuff[1]); + return (client->noClientException); +} + +int +ProcPolyArc(register ClientPtr client) +{ + int narcs; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyArcReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + narcs = (client->req_len << 2) - sizeof(xPolyArcReq); + if (narcs % sizeof(xArc)) + return (BadLength); + narcs /= sizeof(xArc); + if (narcs) + (*pGC->ops->PolyArc) (pDraw, pGC, narcs, (xArc *) & stuff[1]); + return (client->noClientException); +} + +int +ProcFillPoly(register ClientPtr client) +{ + int things; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xFillPolyReq); + + REQUEST_AT_LEAST_SIZE(xFillPolyReq); + if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) && + (stuff->shape != Convex)) { + client->errorValue = stuff->shape; + return BadValue; + } + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) { + client->errorValue = stuff->coordMode; + return BadValue; + } + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + things = ((client->req_len << 2) - sizeof(xFillPolyReq)) >> 2; + if (things) + (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape, + stuff->coordMode, things, + (DDXPointPtr) & stuff[1]); + return (client->noClientException); +} + +int +ProcPolyFillRectangle(register ClientPtr client) +{ + int things; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyFillRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq); + if (things & 4) + return (BadLength); + things >>= 3; + + if (things) + (*pGC->ops->PolyFillRect) (pDraw, pGC, things, + (xRectangle *) &stuff[1]); + return (client->noClientException); +} + +int +ProcPolyFillArc(register ClientPtr client) +{ + int narcs; + + GC *pGC; + + DrawablePtr pDraw; + + REQUEST(xPolyFillArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillArcReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq); + if (narcs % sizeof(xArc)) + return (BadLength); + narcs /= sizeof(xArc); + if (narcs) + (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) & stuff[1]); + return (client->noClientException); +} + +#ifdef MATCH_CLIENT_ENDIAN + +int +ServerOrder(void) +{ + int whichbyte = 1; + + if (*((char *) &whichbyte)) + return LSBFirst; + return MSBFirst; +} + +#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder()) + +void +ReformatImage(char *base, int nbytes, int bpp, int order) +{ + switch (bpp) { + case 1: /* yuck */ + if (BITMAP_BIT_ORDER != order) + BitOrderInvert((unsigned char *) base, nbytes); +#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8 + ReformatImage(base, nbytes, BITMAP_SCANLINE_UNIT, order); +#endif + break; + case 4: + break; /* yuck */ + case 8: + break; + case 16: + if (IMAGE_BYTE_ORDER != order) + TwoByteSwap((unsigned char *) base, nbytes); + break; + case 32: + if (IMAGE_BYTE_ORDER != order) + FourByteSwap((unsigned char *) base, nbytes); + break; + } +} +#else +#define ReformatImage(b,n,bpp,o) +#endif + +/* 64-bit server notes: the protocol restricts padding of images to + * 8-, 16-, or 32-bits. We would like to have 64-bits for the server + * to use internally. Removes need for internal alignment checking. + * All of the PutImage functions could be changed individually, but + * as currently written, they call other routines which require things + * to be 64-bit padded on scanlines, so we changed things here. + * If an image would be padded differently for 64- versus 32-, then + * copy each scanline to a 64-bit padded scanline. + * Also, we need to make sure that the image is aligned on a 64-bit + * boundary, even if the scanlines are padded to our satisfaction. + */ +int +ProcPutImage(register ClientPtr client) +{ + GC *pGC; + + DrawablePtr pDraw; + + long length; /* length of scanline server padded */ + + long lengthProto; /* length of scanline protocol padded */ + + char *tmpImage; + + REQUEST(xPutImageReq); + + REQUEST_AT_LEAST_SIZE(xPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + if (stuff->format == XYBitmap) { + if ((stuff->depth != 1) || + (stuff->leftPad >= (unsigned int) screenInfo.bitmapScanlinePad)) + return BadMatch; + length = BitmapBytePad(stuff->width + stuff->leftPad); + } + else if (stuff->format == XYPixmap) { + if ((pDraw->depth != stuff->depth) || + (stuff->leftPad >= (unsigned int) screenInfo.bitmapScanlinePad)) + return BadMatch; + length = BitmapBytePad(stuff->width + stuff->leftPad); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) { + if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0)) + return BadMatch; + length = PixmapBytePad(stuff->width, stuff->depth); + } + else { + client->errorValue = stuff->format; + return BadValue; + } + + tmpImage = (char *) &stuff[1]; + lengthProto = length; + + if (((((lengthProto * stuff->height) + (unsigned) 3) >> 2) + + (sizeof(xPutImageReq) >> 2)) != client->req_len) + return BadLength; + + ReformatImage(tmpImage, lengthProto * stuff->height, + stuff->format == ZPixmap ? BitsPerPixel(stuff->depth) : 1, + ClientOrder(client)); + + (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY, + stuff->width, stuff->height, + stuff->leftPad, stuff->format, tmpImage); + + return (client->noClientException); +} + +int +DoGetImage(register ClientPtr client, int format, Drawable drawable, + int x, int y, int width, int height, + Mask planemask, xGetImageReply ** im_return) +{ + DrawablePtr pDraw; + + int nlines, linesPerBuf; + + int linesDone; + + long widthBytesLine, length; + + Mask plane = 0; + + char *pBuf; + + xGetImageReply xgi; + + + if ((format != XYPixmap) && (format != ZPixmap)) { + client->errorValue = format; + return (BadValue); + } + SECURITY_VERIFY_DRAWABLE(pDraw, drawable, client, SecurityReadAccess); + if (pDraw->type == DRAWABLE_WINDOW) { + if ( /* check for being viewable */ + !((WindowPtr) pDraw)->realized || + /* check for being on screen */ + pDraw->x + x < 0 || + pDraw->x + x + width > pDraw->pScreen->width || + pDraw->y + y < 0 || + pDraw->y + y + height > pDraw->pScreen->height || + /* check for being inside of border */ + x < -wBorderWidth((WindowPtr) pDraw) || + x + width > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width + || y < -wBorderWidth((WindowPtr) pDraw) || + y + height > + wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height) + return (BadMatch); + xgi.visual = wVisual(((WindowPtr) pDraw)); + } + else { + if (x < 0 || + x + width > (int) pDraw->width || + y < 0 || y + height > (int) pDraw->height) + return (BadMatch); + xgi.visual = None; + } + + SET_DBE_SRCBUF(pDraw, drawable); + + xgi.type = X_Reply; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if (format == ZPixmap) { + widthBytesLine = PixmapBytePad(width, pDraw->depth); + length = widthBytesLine * height; + + } + else { + widthBytesLine = BitmapBytePad(width); + plane = ((Mask) 1) << (pDraw->depth - 1); + /* only planes asked for */ + length = widthBytesLine * height * + Ones(planemask & (plane | (plane - 1))); + + } + + xgi.length = length; + + if (im_return) { + pBuf = malloc(sz_xGetImageReply + length); + if (!pBuf) + return (BadAlloc); + if (widthBytesLine == 0) + linesPerBuf = 0; + else + linesPerBuf = height; + *im_return = (xGetImageReply *) pBuf; + *(xGetImageReply *) pBuf = xgi; + pBuf += sz_xGetImageReply; + } + else { + xgi.length = (xgi.length + 3) >> 2; + if (widthBytesLine == 0 || height == 0) + linesPerBuf = 0; + else if (widthBytesLine >= IMAGE_BUFSIZE) + linesPerBuf = 1; + else { + linesPerBuf = IMAGE_BUFSIZE / widthBytesLine; + if (linesPerBuf > height) + linesPerBuf = height; + } + length = linesPerBuf * widthBytesLine; + if (linesPerBuf < height) { + /* we have to make sure intermediate buffers don't need padding */ + while ((linesPerBuf > 1) && + (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD) - 1))) { + linesPerBuf--; + length -= widthBytesLine; + } + while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD) - 1)) { + linesPerBuf++; + length += widthBytesLine; + } + } + if (!(pBuf = (char *) ALLOCATE_LOCAL(length))) + return (BadAlloc); + WriteReplyToClient(client, sizeof(xGetImageReply), &xgi); + } + + + if (linesPerBuf == 0) { + /* nothing to do */ + } + else if (format == ZPixmap) { + linesDone = 0; + while (height - linesDone > 0) { + nlines = min(linesPerBuf, height - linesDone); + (*pDraw->pScreen->GetImage) (pDraw, + x, + y + linesDone, + width, + nlines, + format, planemask, (pointer) pBuf); + + /* Note that this is NOT a call to WriteSwappedDataToClient, + as we do NOT byte swap */ + if (!im_return) { + ReformatImage(pBuf, (int) (nlines * widthBytesLine), + BitsPerPixel(pDraw->depth), ClientOrder(client)); + +/* Don't split me, gcc pukes when you do */ + (void) WriteToClient(client, + (int) (nlines * widthBytesLine), pBuf); + } + linesDone += nlines; + } + } + else { /* XYPixmap */ + + for (; plane; plane >>= 1) { + if (planemask & plane) { + linesDone = 0; + while (height - linesDone > 0) { + nlines = min(linesPerBuf, height - linesDone); + (*pDraw->pScreen->GetImage) (pDraw, + x, + y + linesDone, + width, + nlines, + format, plane, (pointer) pBuf); + + /* Note: NOT a call to WriteSwappedDataToClient, + as we do NOT byte swap */ + if (im_return) { + pBuf += nlines * widthBytesLine; + } + else { + ReformatImage(pBuf, + (int) (nlines * widthBytesLine), + 1, ClientOrder(client)); + +/* Don't split me, gcc pukes when you do */ + (void) WriteToClient(client, + (int) (nlines * widthBytesLine), + pBuf); + } + linesDone += nlines; + } + } + } + } + if (!im_return) + DEALLOCATE_LOCAL(pBuf); + return (client->noClientException); +} + +int +ProcGetImage(register ClientPtr client) +{ + REQUEST(xGetImageReq); + + REQUEST_SIZE_MATCH(xGetImageReq); + + return DoGetImage(client, stuff->format, stuff->drawable, + stuff->x, stuff->y, + (int) stuff->width, (int) stuff->height, + stuff->planeMask, (xGetImageReply **) NULL); +} + +int +ProcPolyText(register ClientPtr client) +{ + int err; + + REQUEST(xPolyTextReq); + DrawablePtr pDraw; + + GC *pGC; + + REQUEST_AT_LEAST_SIZE(xPolyTextReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + + err = PolyText(client, + pDraw, + pGC, + (unsigned char *) &stuff[1], + ((unsigned char *) stuff) + (client->req_len << 2), + stuff->x, stuff->y, stuff->reqType, stuff->drawable); + + if (err == Success) { + return (client->noClientException); + } + else + return err; +} + +int +ProcImageText8(register ClientPtr client) +{ + int err; + + DrawablePtr pDraw; + + GC *pGC; + + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + + err = ImageText(client, + pDraw, + pGC, + stuff->nChars, + (unsigned char *) &stuff[1], + stuff->x, stuff->y, stuff->reqType, stuff->drawable); + + if (err == Success) { + return (client->noClientException); + } + else + return err; +} + +int +ProcImageText16(register ClientPtr client) +{ + int err; + + DrawablePtr pDraw; + + GC *pGC; + + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + + err = ImageText(client, + pDraw, + pGC, + stuff->nChars, + (unsigned char *) &stuff[1], + stuff->x, stuff->y, stuff->reqType, stuff->drawable); + + if (err == Success) { + return (client->noClientException); + } + else + return err; +} + +int +ProcCreateColormap(register ClientPtr client) +{ + VisualPtr pVisual; + + ColormapPtr pmap; + + Colormap mid; + + WindowPtr pWin; + + ScreenPtr pScreen; + + REQUEST(xCreateColormapReq); + int i, result; + + REQUEST_SIZE_MATCH(xCreateColormapReq); + + if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll)) { + client->errorValue = stuff->alloc; + return (BadValue); + } + mid = stuff->mid; + LEGAL_NEW_RESOURCE(mid, client); + pWin = (WindowPtr) SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return (BadWindow); + + pScreen = pWin->drawable.pScreen; + for (i = 0, pVisual = pScreen->visuals; + i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid != stuff->visual) + continue; + result = CreateColormap(mid, pScreen, pVisual, &pmap, + (int) stuff->alloc, client->index); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); + } + client->errorValue = stuff->visual; + return (BadMatch); +} + +int +ProcFreeColormap(register ClientPtr client) +{ + ColormapPtr pmap; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pmap = (ColormapPtr) SecurityLookupIDByType(client, stuff->id, RT_COLORMAP, + SecurityDestroyAccess); + if (pmap) { + /* Freeing a default colormap is a no-op */ + if (!(pmap->flags & IsDefault)) + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadColor); + } +} + +int +ProcCopyColormapAndFree(register ClientPtr client) +{ + Colormap mid; + + ColormapPtr pSrcMap; + + REQUEST(xCopyColormapAndFreeReq); + int result; + + REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq); + mid = stuff->mid; + LEGAL_NEW_RESOURCE(mid, client); + if ((pSrcMap = (ColormapPtr) SecurityLookupIDByType(client, stuff->srcCmap, + RT_COLORMAP, + SecurityReadAccess | + SecurityWriteAccess))) { + result = CopyColormapAndFree(mid, pSrcMap, client->index); + if (client->noClientException != Success) + return (client->noClientException); + else + return (result); + } + else { + client->errorValue = stuff->srcCmap; + return (BadColor); + } +} + +int +ProcInstallColormap(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->id, + RT_COLORMAP, + SecurityReadAccess); + if (pcmp) { + (*(pcmp->pScreen->InstallColormap)) (pcmp); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadColor); + } +} + +int +ProcUninstallColormap(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->id, + RT_COLORMAP, + SecurityReadAccess); + if (pcmp) { + if (pcmp->mid != pcmp->pScreen->defColormap) + (*(pcmp->pScreen->UninstallColormap)) (pcmp); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadColor); + } +} + +int +ProcListInstalledColormaps(register ClientPtr client) +{ + xListInstalledColormapsReply *preply; + + int nummaps; + + WindowPtr pWin; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr) SecurityLookupWindow(stuff->id, client, + SecurityReadAccess); + + if (!pWin) + return (BadWindow); + + preply = (xListInstalledColormapsReply *) + ALLOCATE_LOCAL(sizeof(xListInstalledColormapsReply) + + pWin->drawable.pScreen->maxInstalledCmaps * + sizeof(Colormap)); + if (!preply) + return (BadAlloc); + + preply->type = X_Reply; + preply->sequenceNumber = client->sequence; + nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pWin->drawable.pScreen, (Colormap *) & preply[1]); + preply->nColormaps = nummaps; + preply->length = nummaps; + WriteReplyToClient(client, sizeof(xListInstalledColormapsReply), preply); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]); + DEALLOCATE_LOCAL(preply); + return (client->noClientException); +} + +int +ProcAllocColor(register ClientPtr client) +{ + ColormapPtr pmap; + + int retval; + + xAllocColorReply acr = {0}; + + REQUEST(xAllocColorReq); + + REQUEST_SIZE_MATCH(xAllocColorReq); + pmap = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pmap) { + acr.type = X_Reply; + acr.length = 0; + acr.sequenceNumber = client->sequence; + acr.red = stuff->red; + acr.green = stuff->green; + acr.blue = stuff->blue; + acr.pixel = 0; + if ((retval = AllocColor(pmap, &acr.red, &acr.green, &acr.blue, + &acr.pixel, client->index))) { + if (client->noClientException != Success) + return (client->noClientException); + else + return (retval); + } + WriteReplyToClient(client, sizeof(xAllocColorReply), &acr); + return (client->noClientException); + + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcAllocNamedColor(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xAllocNamedColorReq); + + REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + int retval; + + xAllocNamedColorReply ancr; + + ancr.type = X_Reply; + ancr.length = 0; + ancr.sequenceNumber = client->sequence; + + if (OsLookupColor + (pcmp->pScreen->myNum, (char *) &stuff[1], stuff->nbytes, + &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue)) { + ancr.screenRed = ancr.exactRed; + ancr.screenGreen = ancr.exactGreen; + ancr.screenBlue = ancr.exactBlue; + ancr.pixel = 0; + if ((retval = AllocColor(pcmp, + &ancr.screenRed, &ancr.screenGreen, + &ancr.screenBlue, &ancr.pixel, + client->index))) { + if (client->noClientException != Success) + return (client->noClientException); + else + return (retval); + } + WriteReplyToClient(client, sizeof(xAllocNamedColorReply), + &ancr); + return (client->noClientException); + } + else + return (BadName); + + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcAllocColorCells(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xAllocColorCellsReq); + + REQUEST_SIZE_MATCH(xAllocColorCellsReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + xAllocColorCellsReply accr; + + int npixels, nmasks, retval; + + long length; + + Pixel *ppixels, *pmasks; + + npixels = stuff->colors; + if (!npixels) { + client->errorValue = npixels; + return (BadValue); + } + if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) { + client->errorValue = stuff->contiguous; + return (BadValue); + } + nmasks = stuff->planes; + length = ((long) npixels + (long) nmasks) * sizeof(Pixel); + ppixels = (Pixel *) ALLOCATE_LOCAL(length); + if (!ppixels) + return (BadAlloc); + pmasks = ppixels + npixels; + + if ((retval = AllocColorCells(client->index, pcmp, npixels, nmasks, + (Bool) stuff->contiguous, ppixels, + pmasks))) { + DEALLOCATE_LOCAL(ppixels); + if (client->noClientException != Success) + return (client->noClientException); + else + return (retval); + } + { + accr.type = X_Reply; + accr.length = length >> 2; + accr.sequenceNumber = client->sequence; + accr.nPixels = npixels; + accr.nMasks = nmasks; + WriteReplyToClient(client, sizeof(xAllocColorCellsReply), &accr); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, length, ppixels); + } + DEALLOCATE_LOCAL(ppixels); + return (client->noClientException); + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcAllocColorPlanes(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xAllocColorPlanesReq); + + REQUEST_SIZE_MATCH(xAllocColorPlanesReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + xAllocColorPlanesReply acpr; + + int npixels, retval; + + long length; + + Pixel *ppixels; + + npixels = stuff->colors; + if (!npixels) { + client->errorValue = npixels; + return (BadValue); + } + if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) { + client->errorValue = stuff->contiguous; + return (BadValue); + } + acpr.type = X_Reply; + acpr.sequenceNumber = client->sequence; + acpr.nPixels = npixels; + length = (long) npixels *sizeof(Pixel); + + ppixels = (Pixel *) ALLOCATE_LOCAL(length); + if (!ppixels) + return (BadAlloc); + if ((retval = AllocColorPlanes(client->index, pcmp, npixels, + (int) stuff->red, (int) stuff->green, + (int) stuff->blue, + (Bool) stuff->contiguous, ppixels, + &acpr.redMask, &acpr.greenMask, + &acpr.blueMask))) { + DEALLOCATE_LOCAL(ppixels); + if (client->noClientException != Success) + return (client->noClientException); + else + return (retval); + } + acpr.length = length >> 2; + { + WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, length, ppixels); + } + DEALLOCATE_LOCAL(ppixels); + return (client->noClientException); + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcFreeColors(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xFreeColorsReq); + + REQUEST_AT_LEAST_SIZE(xFreeColorsReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + int count; + + int retval; + + if (pcmp->flags & AllAllocated) + return (BadAccess); + count = ((client->req_len << 2) - sizeof(xFreeColorsReq)) >> 2; + retval = FreeColors(pcmp, client->index, count, + (Pixel *) & stuff[1], (Pixel) stuff->planeMask); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (retval); + } + + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcStoreColors(ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xStoreColorsReq); + + REQUEST_AT_LEAST_SIZE(xStoreColorsReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + int count; + + int retval; + + count = (client->req_len << 2) - sizeof(xStoreColorsReq); + if (count % sizeof(xColorItem)) + return (BadLength); + count /= sizeof(xColorItem); + retval = StoreColors(pcmp, count, (xColorItem *) & stuff[1]); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (retval); + } + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcStoreNamedColor(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xStoreNamedColorReq); + + REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityWriteAccess); + if (pcmp) { + xColorItem def; + + int retval; + + if (OsLookupColor(pcmp->pScreen->myNum, (char *) &stuff[1], + stuff->nbytes, &def.red, &def.green, &def.blue)) { + def.flags = stuff->flags; + def.pixel = stuff->pixel; + retval = StoreColors(pcmp, 1, &def); + if (client->noClientException != Success) + return (client->noClientException); + else + return (retval); + } + return (BadName); + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcQueryColors(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xQueryColorsReq); + + REQUEST_AT_LEAST_SIZE(xQueryColorsReq); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityReadAccess); + if (pcmp) { + int count, retval; + + xrgb *prgbs; + + xQueryColorsReply qcr = {0}; + + count = ((client->req_len << 2) - sizeof(xQueryColorsReq)) >> 2; + prgbs = (xrgb *) ALLOCATE_LOCAL(count * sizeof(xrgb)); + memset(prgbs, 0, count * sizeof(xrgb)); + if (!prgbs && count) + return (BadAlloc); + if ((retval = QueryColors(pcmp, count, (Pixel *) & stuff[1], prgbs))) { + if (prgbs) + DEALLOCATE_LOCAL(prgbs); + if (client->noClientException != Success) + return (client->noClientException); + else { + client->errorValue = clientErrorValue; + return (retval); + } + } + qcr.type = X_Reply; + qcr.length = (count * sizeof(xrgb)) >> 2; + qcr.sequenceNumber = client->sequence; + qcr.nColors = count; + WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr); + if (count) { + client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend; + WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs); + } + if (prgbs) + DEALLOCATE_LOCAL(prgbs); + return (client->noClientException); + + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcLookupColor(register ClientPtr client) +{ + ColormapPtr pcmp; + + REQUEST(xLookupColorReq); + + REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes); + pcmp = (ColormapPtr) SecurityLookupIDByType(client, stuff->cmap, + RT_COLORMAP, + SecurityReadAccess); + if (pcmp) { + xLookupColorReply lcr = {0}; + + if (OsLookupColor + (pcmp->pScreen->myNum, (char *) &stuff[1], stuff->nbytes, + &lcr.exactRed, &lcr.exactGreen, &lcr.exactBlue)) { + lcr.type = X_Reply; + lcr.length = 0; + lcr.sequenceNumber = client->sequence; + lcr.screenRed = lcr.exactRed; + lcr.screenGreen = lcr.exactGreen; + lcr.screenBlue = lcr.exactBlue; + (*pcmp->pScreen->ResolveColor) (&lcr.screenRed, + &lcr.screenGreen, + &lcr.screenBlue, pcmp->pVisual); + WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr); + return (client->noClientException); + } + return (BadName); + } + else { + client->errorValue = stuff->cmap; + return (BadColor); + } +} + +int +ProcCreateCursor(register ClientPtr client) +{ + CursorPtr pCursor; + + PixmapPtr src; + + PixmapPtr msk; + + unsigned char *srcbits; + + unsigned char *mskbits; + + unsigned short width, height; + + long n; + + CursorMetricRec cm; + + REQUEST(xCreateCursorReq); + + REQUEST_SIZE_MATCH(xCreateCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + + src = (PixmapPtr) SecurityLookupIDByType(client, stuff->source, + RT_PIXMAP, SecurityReadAccess); + msk = (PixmapPtr) SecurityLookupIDByType(client, stuff->mask, + RT_PIXMAP, SecurityReadAccess); + if (src == (PixmapPtr) NULL) { + client->errorValue = stuff->source; + return (BadPixmap); + } + if (msk == (PixmapPtr) NULL) { + if (stuff->mask != None) { + client->errorValue = stuff->mask; + return (BadPixmap); + } + } + else if (src->drawable.width != msk->drawable.width + || src->drawable.height != msk->drawable.height + || src->drawable.depth != 1 || msk->drawable.depth != 1) + return (BadMatch); + + width = src->drawable.width; + height = src->drawable.height; + + if (stuff->x > width || stuff->y > height) + return (BadMatch); + + n = BitmapBytePad(width) * height; + srcbits = malloc(n); + if (!srcbits) + return (BadAlloc); + mskbits = malloc(n); + if (!mskbits) { + free(srcbits); + return (BadAlloc); + } + + /* zeroing the (pad) bits helps some ddx cursor handling */ + bzero((char *) srcbits, n); + (*src->drawable.pScreen->GetImage) ((DrawablePtr) src, 0, 0, width, height, + XYPixmap, 1, (pointer) srcbits); + if (msk == (PixmapPtr) NULL) { + unsigned char *bits = mskbits; + + while (--n >= 0) + *bits++ = ~0; + } + else { + /* zeroing the (pad) bits helps some ddx cursor handling */ + bzero((char *) mskbits, n); + (*msk->drawable.pScreen->GetImage) ((DrawablePtr) msk, 0, 0, width, + height, XYPixmap, 1, + (pointer) mskbits); + } + cm.width = width; + cm.height = height; + cm.xhot = stuff->x; + cm.yhot = stuff->y; + pCursor = AllocCursor(srcbits, mskbits, &cm, + stuff->foreRed, stuff->foreGreen, stuff->foreBlue, + stuff->backRed, stuff->backGreen, stuff->backBlue); + + if (pCursor && AddResource(stuff->cid, RT_CURSOR, (pointer) pCursor)) + return (client->noClientException); + return BadAlloc; +} + +int +ProcCreateGlyphCursor(register ClientPtr client) +{ + CursorPtr pCursor; + + int res; + + REQUEST(xCreateGlyphCursorReq); + + REQUEST_SIZE_MATCH(xCreateGlyphCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + + res = AllocGlyphCursor(stuff->source, stuff->sourceChar, + stuff->mask, stuff->maskChar, + stuff->foreRed, stuff->foreGreen, stuff->foreBlue, + stuff->backRed, stuff->backGreen, stuff->backBlue, + &pCursor, client); + if (res != Success) + return res; + if (AddResource(stuff->cid, RT_CURSOR, (pointer) pCursor)) + return client->noClientException; + return BadAlloc; +} + +int +ProcFreeCursor(register ClientPtr client) +{ + CursorPtr pCursor; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pCursor = (CursorPtr) SecurityLookupIDByType(client, stuff->id, + RT_CURSOR, + SecurityDestroyAccess); + if (pCursor) { + FreeResource(stuff->id, RT_NONE); + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadCursor); + } +} + +int +ProcQueryBestSize(register ClientPtr client) +{ + xQueryBestSizeReply reply = {0}; + + DrawablePtr pDraw; + + ScreenPtr pScreen; + + REQUEST(xQueryBestSizeReq); + + REQUEST_SIZE_MATCH(xQueryBestSizeReq); + if ((stuff->class != CursorShape) && + (stuff->class != TileShape) && (stuff->class != StippleShape)) { + client->errorValue = stuff->class; + return (BadValue); + } + SECURITY_VERIFY_GEOMETRABLE(pDraw, stuff->drawable, client, + SecurityReadAccess); + if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW) + return (BadMatch); + pScreen = pDraw->pScreen; + (*pScreen->QueryBestSize) (stuff->class, &stuff->width, + &stuff->height, pScreen); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.width = stuff->width; + reply.height = stuff->height; + WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply); + return (client->noClientException); +} + +int +ProcSetScreenSaver(register ClientPtr client) +{ + int blankingOption, exposureOption; + + REQUEST(xSetScreenSaverReq); + + REQUEST_SIZE_MATCH(xSetScreenSaverReq); + blankingOption = stuff->preferBlank; + if ((blankingOption != DontPreferBlanking) && + (blankingOption != PreferBlanking) && + (blankingOption != DefaultBlanking)) { + client->errorValue = blankingOption; + return BadValue; + } + exposureOption = stuff->allowExpose; + if ((exposureOption != DontAllowExposures) && + (exposureOption != AllowExposures) && + (exposureOption != DefaultExposures)) { + client->errorValue = exposureOption; + return BadValue; + } + if (stuff->timeout < -1) { + client->errorValue = stuff->timeout; + return BadValue; + } + if (stuff->interval < -1) { + client->errorValue = stuff->interval; + return BadValue; + } + + if (blankingOption == DefaultBlanking) + ScreenSaverBlanking = defaultScreenSaverBlanking; + else + ScreenSaverBlanking = blankingOption; + if (exposureOption == DefaultExposures) + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; + else + ScreenSaverAllowExposures = exposureOption; + + if (stuff->timeout >= 0) + ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND; + else + ScreenSaverTime = defaultScreenSaverTime; + if (stuff->interval >= 0) + ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND; + else + ScreenSaverInterval = defaultScreenSaverInterval; + + SetScreenSaverTimer(); + return (client->noClientException); +} + +int +ProcGetScreenSaver(register ClientPtr client) +{ + xGetScreenSaverReply rep; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.timeout = ScreenSaverTime / MILLI_PER_SECOND; + rep.interval = ScreenSaverInterval / MILLI_PER_SECOND; + rep.preferBlanking = ScreenSaverBlanking; + rep.allowExposures = ScreenSaverAllowExposures; + WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep); + return (client->noClientException); +} + +int +ProcChangeHosts(register ClientPtr client) +{ + REQUEST(xChangeHostsReq); + int result; + + REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength); + + if (stuff->mode == HostInsert) + result = AddHost(client, (int) stuff->hostFamily, + stuff->hostLength, (pointer) &stuff[1]); + else if (stuff->mode == HostDelete) + result = RemoveHost(client, (int) stuff->hostFamily, + stuff->hostLength, (pointer) &stuff[1]); + else { + client->errorValue = stuff->mode; + return BadValue; + } + if (!result) + result = client->noClientException; + return (result); +} + +int +ProcListHosts(register ClientPtr client) +{ + xListHostsReply reply; + + int len, nHosts, result; + + pointer pdata; + + /* REQUEST(xListHostsReq); */ + + REQUEST_SIZE_MATCH(xListHostsReq); + result = GetHosts(&pdata, &nHosts, &len, &reply.enabled); + if (result != Success) + return (result); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.nHosts = nHosts; + reply.length = len >> 2; + WriteReplyToClient(client, sizeof(xListHostsReply), &reply); + if (nHosts) { + client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend; + WriteSwappedDataToClient(client, len, pdata); + } + free(pdata); + return (client->noClientException); +} + +int +ProcChangeAccessControl(register ClientPtr client) +{ + int result; + + REQUEST(xSetAccessControlReq); + + REQUEST_SIZE_MATCH(xSetAccessControlReq); + if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess)) { + client->errorValue = stuff->mode; + return BadValue; + } + result = ChangeAccessControl(client, stuff->mode == EnableAccess); + if (!result) + result = client->noClientException; + return (result); +} + +int +ProcKillClient(register ClientPtr client) +{ + REQUEST(xResourceReq); + ClientPtr killclient; + + REQUEST_SIZE_MATCH(xResourceReq); + if (stuff->id == AllTemporary) { + CloseDownRetainedResources(); + return (client->noClientException); + } + + if ((killclient = LookupClient(stuff->id, client))) { + CloseDownClient(killclient); + /* if an LBX proxy gets killed, isItTimeToYield will be set */ + if (isItTimeToYield || (client == killclient)) { + /* force yield and return Success, so that Dispatch() + * doesn't try to touch client + */ + isItTimeToYield = TRUE; + return (Success); + } + return (client->noClientException); + } + else { + client->errorValue = stuff->id; + return (BadValue); + } +} + +int +ProcSetFontPath(register ClientPtr client) +{ + unsigned char *ptr; + + unsigned long nbytes, total; + + long nfonts; + + int n, result; + + int error; + + REQUEST(xSetFontPathReq); + + REQUEST_AT_LEAST_SIZE(xSetFontPathReq); + + nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); + total = nbytes; + ptr = (unsigned char *) &stuff[1]; + nfonts = stuff->nFonts; + while (--nfonts >= 0) { + if ((total == 0) || (total < (n = (*ptr + 1)))) + return (BadLength); + total -= n; + ptr += n; + } + if (total >= 4) + return (BadLength); + result = SetFontPath(client, stuff->nFonts, (unsigned char *) &stuff[1], + &error); + if (!result) { + result = client->noClientException; + client->errorValue = error; + } + return (result); +} + +int +ProcGetFontPath(register ClientPtr client) +{ + xGetFontPathReply reply; + + int stringLens, numpaths; + + unsigned char *bufferStart; + + /* REQUEST (xReq); */ + + REQUEST_SIZE_MATCH(xReq); + bufferStart = GetFontPath(&numpaths, &stringLens); + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = (stringLens + numpaths + 3) >> 2; + reply.nPaths = numpaths; + + WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply); + if (stringLens || numpaths) + (void) WriteToClient(client, stringLens + numpaths, + (char *) bufferStart); + return (client->noClientException); +} + +int +ProcChangeCloseDownMode(register ClientPtr client) +{ + REQUEST(xSetCloseDownModeReq); + + REQUEST_SIZE_MATCH(xSetCloseDownModeReq); + if ((stuff->mode == AllTemporary) || + (stuff->mode == RetainPermanent) || (stuff->mode == RetainTemporary)) { + client->closeDownMode = stuff->mode; + return (client->noClientException); + } + else { + client->errorValue = stuff->mode; + return (BadValue); + } +} + +int +ProcForceScreenSaver(register ClientPtr client) +{ + REQUEST(xForceScreenSaverReq); + + REQUEST_SIZE_MATCH(xForceScreenSaverReq); + + if ((stuff->mode != ScreenSaverReset) && (stuff->mode != ScreenSaverActive)) { + client->errorValue = stuff->mode; + return BadValue; + } + SaveScreens(SCREEN_SAVER_FORCER, (int) stuff->mode); + return client->noClientException; +} + +int +ProcNoOperation(register ClientPtr client) +{ + REQUEST_AT_LEAST_SIZE(xReq); + + /* noop -- don't do anything */ + return (client->noClientException); +} + +/********************** + * CloseDownClient + * + * Client can either mark his resources destroy or retain. If retained and + * then killed again, the client is really destroyed. + *********************/ + +char dispatchExceptionAtReset = DE_RESET; + +void +CloseDownClient(register ClientPtr client) +{ + Bool really_close_down = client->clientGone || + client->closeDownMode == DestroyAll; + + if (!client->clientGone) { + /* ungrab server if grabbing client dies */ + if (grabState != GrabNone && grabClient == client) { + UngrabServer(client); + } + BITCLEAR(grabWaiters, client->index); + DeleteClientFromAnySelections(client); + ReleaseActiveGrabs(client); + DeleteClientFontStuff(client); + if (!really_close_down) { + /* This frees resources that should never be retained + * no matter what the close down mode is. Actually we + * could do this unconditionally, but it's probably + * better not to traverse all the client's resources + * twice (once here, once a few lines down in + * FreeClientResources) in the common case of + * really_close_down == TRUE. + */ + FreeClientNeverRetainResources(client); + client->clientState = ClientStateRetained; + if (ClientStateCallback) { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *) NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); + } + } + client->clientGone = TRUE; /* so events aren't sent to client */ + if (ClientIsAsleep(client)) + ClientSignal(client); + ProcessWorkQueueZombies(); + CloseDownConnection(client); + + /* If the client made it to the Running stage, nClients has + * been incremented on its behalf, so we need to decrement it + * now. If it hasn't gotten to Running, nClients has *not* + * been incremented, so *don't* decrement it. + */ + if (client->clientState != ClientStateInitial && + client->clientState != ClientStateAuthenticating) { + --nClients; + } + } + + if (really_close_down) { + if (client->clientState == ClientStateRunning && nClients == 0) + dispatchException |= dispatchExceptionAtReset; + + client->clientState = ClientStateGone; + if (ClientStateCallback) { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *) NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); + } + FreeClientResources(client); + if (client->index < nextFreeClientID) + nextFreeClientID = client->index; + clients[client->index] = NullClient; +#ifdef SMART_SCHEDULE + SmartLastClient = NullClient; +#endif + free(client); + + while (!clients[currentMaxClients - 1]) + currentMaxClients--; + } +} + +static void +KillAllClients() +{ + int i; + + for (i = 1; i < currentMaxClients; i++) + if (clients[i]) { + /* Make sure Retained clients are released. */ + clients[i]->closeDownMode = DestroyAll; + CloseDownClient(clients[i]); + } +} + +/********************* + * CloseDownRetainedResources + * + * Find all clients that are gone and have terminated in RetainTemporary + * and destroy their resources. + *********************/ + +void +CloseDownRetainedResources() +{ + int i; + + ClientPtr client; + + for (i = 1; i < currentMaxClients; i++) { + client = clients[i]; + if (client && (client->closeDownMode == RetainTemporary) + && (client->clientGone)) + CloseDownClient(client); + } +} + +extern int clientPrivateLen; + +extern unsigned *clientPrivateSizes; + +extern unsigned totalClientSize; + +void +InitClient(ClientPtr client, int i, pointer ospriv) +{ + client->index = i; + client->sequence = 0; + client->clientAsMask = ((Mask) i) << CLIENTOFFSET; + client->clientGone = FALSE; + if (i) { + client->closeDownMode = DestroyAll; + client->lastDrawable = (DrawablePtr) WindowTable[0]; + client->lastDrawableID = WindowTable[0]->drawable.id; + } + else { + client->closeDownMode = RetainPermanent; + client->lastDrawable = (DrawablePtr) NULL; + client->lastDrawableID = INVALID; + } + client->lastGC = (GCPtr) NULL; + client->lastGCID = INVALID; + client->numSaved = 0; + client->saveSet = (SaveSetElt *) NULL; + client->noClientException = Success; +#ifdef DEBUG + client->requestLogIndex = 0; +#endif + client->requestVector = InitialVector; + client->osPrivate = ospriv; + client->swapped = FALSE; + client->big_requests = FALSE; + client->priority = 0; + client->clientState = ClientStateInitial; + client->replyBytesRemaining = 0; + client->fontResFunc = NULL; +#ifdef SMART_SCHEDULE + client->smart_priority = 0; + client->smart_start_tick = SmartScheduleTime; + client->smart_stop_tick = SmartScheduleTime; + client->smart_check_tick = SmartScheduleTime; +#endif +} + +int +InitClientPrivates(ClientPtr client) +{ + char *ptr; + + DevUnion *ppriv; + + unsigned *sizes; + + unsigned size; + + int i; + + if (totalClientSize == sizeof(ClientRec)) + ppriv = (DevUnion *) NULL; + else if (client->index) + ppriv = (DevUnion *) (client + 1); + else { + ppriv = malloc(totalClientSize - sizeof(ClientRec)); + if (!ppriv) + return 0; + } + client->devPrivates = ppriv; + sizes = clientPrivateSizes; + ptr = (char *) (ppriv + clientPrivateLen); + for (i = clientPrivateLen; --i >= 0; ppriv++, sizes++) { + if ((size = *sizes)) { + ppriv->ptr = (pointer) ptr; + ptr += size; + } + else + ppriv->ptr = (pointer) NULL; + } + + /* Allow registrants to initialize the serverClient devPrivates */ + if (!client->index && ClientStateCallback) { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *) NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); + } + return 1; +} + +/************************ + * int NextAvailableClient(ospriv) + * + * OS dependent portion can't assign client id's because of CloseDownModes. + * Returns NULL if there are no free clients. + *************************/ + +ClientPtr +NextAvailableClient(pointer ospriv) +{ + int i; + + ClientPtr client; + + xReq data; + + i = nextFreeClientID; + if (i == MAXCLIENTS) + return (ClientPtr) NULL; + clients[i] = client = malloc(totalClientSize); + if (!client) + return (ClientPtr) NULL; + InitClient(client, i, ospriv); + InitClientPrivates(client); + if (!InitClientResources(client)) { + free(client); + return (ClientPtr) NULL; + } + data.reqType = 1; + data.length = (sz_xReq + sz_xConnClientPrefix) >> 2; + if (!InsertFakeRequest(client, (char *) &data, sz_xReq)) { + FreeClientResources(client); + free(client); + return (ClientPtr) NULL; + } + if (i == currentMaxClients) + currentMaxClients++; + while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID]) + nextFreeClientID++; + if (ClientStateCallback) { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *) NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); + } + return (client); +} + +int +ProcInitialConnection(register ClientPtr client) +{ + REQUEST(xReq); + xConnClientPrefix *prefix; + + int whichbyte = 1; + + prefix = (xConnClientPrefix *) ((char *) stuff + sz_xReq); + if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B')) + return (client->noClientException = -1); + if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) { + client->swapped = TRUE; + SwapConnClientPrefix(prefix); + } + stuff->reqType = 2; + stuff->length += ((prefix->nbytesAuthProto + (unsigned) 3) >> 2) + + ((prefix->nbytesAuthString + (unsigned) 3) >> 2); + if (client->swapped) { + swaps(&stuff->length); + } + ResetCurrentRequest(client); + return (client->noClientException); +} + +int +SendConnSetup(register ClientPtr client, const char *reason) +{ + xWindowRoot *root; + + int i; + + int numScreens; + + char *lConnectionInfo; + + xConnSetupPrefix *lconnSetupPrefix; + + if (reason) { + xConnSetupPrefix csp; + + csp.success = xFalse; + csp.lengthReason = strlen(reason); + csp.length = (csp.lengthReason + (unsigned) 3) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (client->swapped) + WriteSConnSetupPrefix(client, &csp); + else + (void) WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp); + (void) WriteToClient(client, (int) csp.lengthReason, reason); + return (client->noClientException = -1); + } + + numScreens = screenInfo.numScreens; + lConnectionInfo = ConnectionInfo; + lconnSetupPrefix = &connSetupPrefix; + + /* We're about to start speaking X protocol back to the client by + * sending the connection setup info. This means the authorization + * step is complete, and we can count the client as an + * authorized one. + */ + nClients++; + + client->requestVector = client->swapped ? SwappedProcVector : ProcVector; + client->sequence = 0; + ((xConnSetup *) lConnectionInfo)->ridBase = client->clientAsMask; + ((xConnSetup *) lConnectionInfo)->ridMask = RESOURCE_ID_MASK; +#ifdef MATCH_CLIENT_ENDIAN + ((xConnSetup *) lConnectionInfo)->imageByteOrder = ClientOrder(client); + ((xConnSetup *) lConnectionInfo)->bitmapBitOrder = ClientOrder(client); +#endif + /* fill in the "currentInputMask" */ + root = (xWindowRoot *) (lConnectionInfo + connBlockScreenStart); + + for (i = 0; i < numScreens; i++) { + unsigned int j; + + xDepth *pDepth; + + root->currentInputMask = WindowTable[i]->eventMask | + wOtherEventMasks(WindowTable[i]); + pDepth = (xDepth *) (root + 1); + for (j = 0; j < root->nDepths; j++) { + pDepth = (xDepth *) (((char *) (pDepth + 1)) + + pDepth->nVisuals * sizeof(xVisualType)); + } + root = (xWindowRoot *) pDepth; + } + + if (client->swapped) { + WriteSConnSetupPrefix(client, lconnSetupPrefix); + WriteSConnectionInfo(client, + (unsigned long) (lconnSetupPrefix->length << 2), + lConnectionInfo); + } + else { + (void) WriteToClient(client, sizeof(xConnSetupPrefix), + (char *) lconnSetupPrefix); + (void) WriteToClient(client, (int) (lconnSetupPrefix->length << 2), + lConnectionInfo); + } + client->clientState = ClientStateRunning; + if (ClientStateCallback) { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = lconnSetupPrefix; + clientinfo.setup = (xConnSetup *) lConnectionInfo; + CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); + } + return (client->noClientException); +} + +int +ProcEstablishConnection(register ClientPtr client) +{ + const char *reason; + char *auth_proto, *auth_string; + + xConnClientPrefix *prefix; + + REQUEST(xReq); + + prefix = (xConnClientPrefix *) ((char *) stuff + sz_xReq); + auth_proto = (char *) prefix + sz_xConnClientPrefix; + auth_string = auth_proto + ((prefix->nbytesAuthProto + 3) & ~3); + if ((prefix->majorVersion != X_PROTOCOL) || + (prefix->minorVersion != X_PROTOCOL_REVISION)) + reason = "Protocol version mismatch"; + else + reason = ClientAuthorized(client, + (unsigned short) prefix->nbytesAuthProto, + auth_proto, + (unsigned short) prefix->nbytesAuthString, + auth_string); + /* + * If Kerberos is being used for this client, the clientState + * will be set to ClientStateAuthenticating at this point. + * More messages need to be exchanged among the X server, Kerberos + * server, and client to figure out if everyone is authorized. + * So we don't want to send the connection setup info yet, since + * the auth step isn't really done. + */ + if (client->clientState == ClientStateCheckingSecurity) + client->clientState = ClientStateCheckedSecurity; + else if (client->clientState != ClientStateAuthenticating) + return (SendConnSetup(client, reason)); + return (client->noClientException); +} + +_X_EXPORT void +SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode, + XID resId, int errorCode) +{ + xError rep; + + rep.type = X_Error; + rep.sequenceNumber = client->sequence; + rep.errorCode = errorCode; + rep.majorCode = majorCode; + rep.minorCode = minorCode; + rep.resourceID = resId; + + WriteEventsToClient(client, 1, (xEvent *) &rep); +} + +void +DeleteWindowFromAnySelections(WindowPtr pWin) +{ + int i; + + for (i = 0; i < NumCurrentSelections; i++) + if (CurrentSelections[i].pWin == pWin) { + if (SelectionCallback) { + SelectionInfoRec info; + + info.selection = &CurrentSelections[i]; + info.kind = SelectionWindowDestroy; + CallCallbacks(&SelectionCallback, &info); + } + CurrentSelections[i].pWin = (WindowPtr) NULL; + CurrentSelections[i].window = None; + CurrentSelections[i].client = NullClient; + } +} + +static void +DeleteClientFromAnySelections(ClientPtr client) +{ + int i; + + for (i = 0; i < NumCurrentSelections; i++) + if (CurrentSelections[i].client == client) { + if (SelectionCallback) { + SelectionInfoRec info; + + info.selection = &CurrentSelections[i]; + info.kind = SelectionWindowDestroy; + CallCallbacks(&SelectionCallback, &info); + } + CurrentSelections[i].pWin = (WindowPtr) NULL; + CurrentSelections[i].window = None; + CurrentSelections[i].client = NullClient; + } +} + +void +MarkClientException(ClientPtr client) +{ + client->noClientException = -1; +} diff --git a/dix/dispatch.h b/dix/dispatch.h new file mode 100644 index 0000000..4b71b5a --- /dev/null +++ b/dix/dispatch.h @@ -0,0 +1,146 @@ +/************************************************************ + +Copyright 1996 by Thomas E. Dickey + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the above listed +copyright holder(s) not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD +TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE +LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + * This prototypes the dispatch.c module (except for functions declared in + * global headers), plus related dispatch procedures from devices.c, events.c, + * extension.c, property.c. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifndef DISPATCH_H +#define DISPATCH_H 1 + +DISPATCH_PROC(InitClientPrivates); +DISPATCH_PROC(ProcAllocColor); +DISPATCH_PROC(ProcAllocColorCells); +DISPATCH_PROC(ProcAllocColorPlanes); +DISPATCH_PROC(ProcAllocNamedColor); +DISPATCH_PROC(ProcBell); +DISPATCH_PROC(ProcChangeAccessControl); +DISPATCH_PROC(ProcChangeCloseDownMode); +DISPATCH_PROC(ProcChangeGC); +DISPATCH_PROC(ProcChangeHosts); +DISPATCH_PROC(ProcChangeKeyboardControl); +DISPATCH_PROC(ProcChangeKeyboardMapping); +DISPATCH_PROC(ProcChangePointerControl); +DISPATCH_PROC(ProcChangeProperty); +DISPATCH_PROC(ProcChangeSaveSet); +DISPATCH_PROC(ProcChangeWindowAttributes); +DISPATCH_PROC(ProcCirculateWindow); +DISPATCH_PROC(ProcClearToBackground); +DISPATCH_PROC(ProcCloseFont); +DISPATCH_PROC(ProcConfigureWindow); +DISPATCH_PROC(ProcConvertSelection); +DISPATCH_PROC(ProcCopyArea); +DISPATCH_PROC(ProcCopyColormapAndFree); +DISPATCH_PROC(ProcCopyGC); +DISPATCH_PROC(ProcCopyPlane); +DISPATCH_PROC(ProcCreateColormap); +DISPATCH_PROC(ProcCreateCursor); +DISPATCH_PROC(ProcCreateGC); +DISPATCH_PROC(ProcCreateGlyphCursor); +DISPATCH_PROC(ProcCreatePixmap); +DISPATCH_PROC(ProcCreateWindow); +DISPATCH_PROC(ProcDeleteProperty); +DISPATCH_PROC(ProcDestroySubwindows); +DISPATCH_PROC(ProcDestroyWindow); +DISPATCH_PROC(ProcEstablishConnection); +DISPATCH_PROC(ProcFillPoly); +DISPATCH_PROC(ProcForceScreenSaver); +DISPATCH_PROC(ProcFreeColormap); +DISPATCH_PROC(ProcFreeColors); +DISPATCH_PROC(ProcFreeCursor); +DISPATCH_PROC(ProcFreeGC); +DISPATCH_PROC(ProcFreePixmap); +DISPATCH_PROC(ProcGetAtomName); +DISPATCH_PROC(ProcGetFontPath); +DISPATCH_PROC(ProcGetGeometry); +DISPATCH_PROC(ProcGetImage); +DISPATCH_PROC(ProcGetKeyboardControl); +DISPATCH_PROC(ProcGetKeyboardMapping); +DISPATCH_PROC(ProcGetModifierMapping); +DISPATCH_PROC(ProcGetMotionEvents); +DISPATCH_PROC(ProcGetPointerControl); +DISPATCH_PROC(ProcGetPointerMapping); +DISPATCH_PROC(ProcGetProperty); +DISPATCH_PROC(ProcGetScreenSaver); +DISPATCH_PROC(ProcGetSelectionOwner); +DISPATCH_PROC(ProcGetWindowAttributes); +DISPATCH_PROC(ProcGrabServer); +DISPATCH_PROC(ProcImageText16); +DISPATCH_PROC(ProcImageText8); +DISPATCH_PROC(ProcInitialConnection); +DISPATCH_PROC(ProcInstallColormap); +DISPATCH_PROC(ProcInternAtom); +DISPATCH_PROC(ProcKillClient); +DISPATCH_PROC(ProcListExtensions); +DISPATCH_PROC(ProcListFonts); +DISPATCH_PROC(ProcListFontsWithInfo); +DISPATCH_PROC(ProcListHosts); +DISPATCH_PROC(ProcListInstalledColormaps); +DISPATCH_PROC(ProcListProperties); +DISPATCH_PROC(ProcLookupColor); +DISPATCH_PROC(ProcMapSubwindows); +DISPATCH_PROC(ProcMapWindow); +DISPATCH_PROC(ProcNoOperation); +DISPATCH_PROC(ProcOpenFont); +DISPATCH_PROC(ProcPolyArc); +DISPATCH_PROC(ProcPolyFillArc); +DISPATCH_PROC(ProcPolyFillRectangle); +DISPATCH_PROC(ProcPolyLine); +DISPATCH_PROC(ProcPolyPoint); +DISPATCH_PROC(ProcPolyRectangle); +DISPATCH_PROC(ProcPolySegment); +DISPATCH_PROC(ProcPolyText); +DISPATCH_PROC(ProcPutImage); +DISPATCH_PROC(ProcQueryBestSize); +DISPATCH_PROC(ProcQueryColors); +DISPATCH_PROC(ProcQueryExtension); +DISPATCH_PROC(ProcQueryFont); +DISPATCH_PROC(ProcQueryKeymap); +DISPATCH_PROC(ProcQueryTextExtents); +DISPATCH_PROC(ProcQueryTree); +DISPATCH_PROC(ProcReparentWindow); +DISPATCH_PROC(ProcRotateProperties); +DISPATCH_PROC(ProcSetClipRectangles); +DISPATCH_PROC(ProcSetDashes); +DISPATCH_PROC(ProcSetFontPath); +DISPATCH_PROC(ProcSetModifierMapping); +DISPATCH_PROC(ProcSetPointerMapping); +DISPATCH_PROC(ProcSetScreenSaver); +DISPATCH_PROC(ProcSetSelectionOwner); +DISPATCH_PROC(ProcStoreColors); +DISPATCH_PROC(ProcStoreNamedColor); +DISPATCH_PROC(ProcTranslateCoords); +DISPATCH_PROC(ProcUngrabServer); +DISPATCH_PROC(ProcUninstallColormap); +DISPATCH_PROC(ProcUnmapSubwindows); +DISPATCH_PROC(ProcUnmapWindow); + +#endif /* DISPATCH_H */ diff --git a/dix/dixfonts.c b/dix/dixfonts.c new file mode 100644 index 0000000..b3ed865 --- /dev/null +++ b/dix/dixfonts.c @@ -0,0 +1,2053 @@ +/************************************************************************ +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ +/* The panoramix components contained the following notice */ +/* +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include "scrnintstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "misc.h" +#include "opaque.h" +#include "dixfontstr.h" +#include "closestr.h" + +#ifdef XF86BIGFONT +#define _XF86BIGFONT_SERVER_ +#include +#include "xf86bigfontsrv.h" +#endif + +#define QUERYCHARINFO(pci, pr) *(pr) = (pci)->metrics + +extern pointer fosNaturalParams; + +extern FontPtr defaultFont; + +static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0; + +static int num_fpes = 0; + +_X_EXPORT FPEFunctions *fpe_functions = (FPEFunctions *) 0; + +static int num_fpe_types = 0; + +static unsigned char *font_path_string; + +static int num_slept_fpes = 0; + +static int size_slept_fpes = 0; + +static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0; + +static FontPatternCachePtr patternCache; + +_X_EXPORT int +FontToXError(err) +int err; +{ + switch (err) { + case Successful: + return Success; + case AllocError: + return BadAlloc; + case BadFontName: + return BadName; + case BadFontPath: + case BadFontFormat: /* is there something better? */ + case BadCharRange: + return BadValue; + default: + return err; + } +} + +/* + * adding RT_FONT prevents conflict with default cursor font + */ +Bool +SetDefaultFont(char *defaultfontname) +{ + int err; + + FontPtr pf; + + XID fid; + + fid = FakeClientID(0); + err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync, + (unsigned) strlen(defaultfontname), defaultfontname); + if (err != Success) + return FALSE; + pf = (FontPtr) LookupIDByType(fid, RT_FONT); + if (pf == (FontPtr) NULL) + return FALSE; + defaultFont = pf; + return TRUE; +} + +/* + * note that the font wakeup queue is not refcounted. this is because + * an fpe needs to be added when it's inited, and removed when it's finally + * freed, in order to handle any data that isn't requested, like FS events. + * + * since the only thing that should call these routines is the renderer's + * init_fpe() and free_fpe(), there shouldn't be any problem in using + * freed data. + */ +void +QueueFontWakeup(FontPathElementPtr fpe) +{ + int i; + + FontPathElementPtr *new; + + for (i = 0; i < num_slept_fpes; i++) { + if (slept_fpes[i] == fpe) { + + + return; + } + } + if (num_slept_fpes == size_slept_fpes) { + new = (FontPathElementPtr *) + realloc(slept_fpes, + sizeof(FontPathElementPtr) * (size_slept_fpes + 4)); + if (!new) + return; + slept_fpes = new; + size_slept_fpes += 4; + } + slept_fpes[num_slept_fpes] = fpe; + num_slept_fpes++; +} + +void +RemoveFontWakeup(FontPathElementPtr fpe) +{ + int i, j; + + for (i = 0; i < num_slept_fpes; i++) { + if (slept_fpes[i] == fpe) { + for (j = i; j < num_slept_fpes; j++) { + slept_fpes[j] = slept_fpes[j + 1]; + } + num_slept_fpes--; + return; + } + } +} + +void +FontWakeup(pointer data, int count, pointer LastSelectMask) +{ + int i; + + FontPathElementPtr fpe; + + if (count < 0) + return; + /* wake up any fpe's that may be waiting for information */ + for (i = 0; i < num_slept_fpes; i++) { + fpe = slept_fpes[i]; + (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask); + } +} + +/* XXX -- these two funcs may want to be broken into macros */ +static void +UseFPE(FontPathElementPtr fpe) +{ + fpe->refcount++; +} + +static void +FreeFPE(FontPathElementPtr fpe) +{ + fpe->refcount--; + if (fpe->refcount == 0) { + (*fpe_functions[fpe->type].free_fpe) (fpe); + free(fpe->name); + free(fpe); + } +} + +static Bool +doOpenFont(ClientPtr client, OFclosurePtr c) +{ + FontPtr pfont = NullFont; + + FontPathElementPtr fpe = NULL; + + ScreenPtr pScr; + + int err = Successful; + + int i; + + char *alias, *newname; + + int newlen; + + int aliascount = 20; + + /* + * Decide at runtime what FontFormat to use. + */ + Mask FontFormat = + ((screenInfo.imageByteOrder == LSBFirst) ? + BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) | + ((screenInfo.bitmapBitOrder == LSBFirst) ? + BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) | + BitmapFormatImageRectMin | +#if GLYPHPADBYTES == 1 + BitmapFormatScanlinePad8 | +#endif +#if GLYPHPADBYTES == 2 + BitmapFormatScanlinePad16 | +#endif +#if GLYPHPADBYTES == 4 + BitmapFormatScanlinePad32 | +#endif +#if GLYPHPADBYTES == 8 + BitmapFormatScanlinePad64 | +#endif + BitmapFormatScanlineUnit8; + + if (client->clientGone) { + if (c->current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } + err = Successful; + goto bail; + } + while (c->current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current_fpe]; + err = (*fpe_functions[fpe->type].open_font) + ((pointer) client, fpe, c->flags, + c->fontname, c->fnamelen, FontFormat, + BitmapFormatMaskByte | + BitmapFormatMaskBit | + BitmapFormatMaskImageRectangle | + BitmapFormatMaskScanLinePad | + BitmapFormatMaskScanLineUnit, + c->fontid, &pfont, &alias, + c->non_cachable_font && c->non_cachable_font->fpe == fpe ? + c->non_cachable_font : (FontPtr) 0); + + if (err == FontNameAlias && alias) { + newlen = strlen(alias); + newname = (char *) realloc(c->fontname, newlen); + if (!newname) { + err = AllocError; + break; + } + memmove(newname, alias, newlen); + c->fontname = newname; + c->fnamelen = newlen; + c->current_fpe = 0; + if (--aliascount <= 0) + break; + continue; + } + if (err == BadFontName) { + c->current_fpe++; + continue; + } + if (err == Suspended) { + if (!c->slept) { + c->slept = TRUE; + ClientSleep(client, (ClientSleepProcPtr) doOpenFont, + (pointer) c); + } + return TRUE; + } + break; + } + + if (err != Successful) + goto bail; + if (!pfont) { + err = BadFontName; + goto bail; + } + if (!pfont->fpe) + pfont->fpe = fpe; + pfont->refcnt++; + if (pfont->refcnt == 1) { + UseFPE(pfont->fpe); + for (i = 0; i < screenInfo.numScreens; i++) { + pScr = screenInfo.screens[i]; + if (pScr->RealizeFont) { + if (!(*pScr->RealizeFont) (pScr, pfont)) { + CloseFont(pfont, (Font) 0); + err = AllocError; + goto bail; + } + } + } + } + if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) { + err = AllocError; + goto bail; + } + if (patternCache && pfont != c->non_cachable_font) + CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen, + pfont); + bail: + if (err != Successful && c->client != serverClient) { + SendErrorToClient(c->client, X_OpenFont, 0, + c->fontid, FontToXError(err)); + } + if (c->slept) + ClientWakeup(c->client); + for (i = 0; i < c->num_fpes; i++) { + FreeFPE(c->fpe_list[i]); + } + free(c->fpe_list); + free(c->fontname); + free(c); + return TRUE; +} + +int +OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, + char *pfontname) +{ + OFclosurePtr c; + + int i; + + FontPtr cached = (FontPtr) 0; + +#ifdef FONTDEBUG + char *f; + + f = malloc(lenfname + 1); + memmove(f, pfontname, lenfname); + f[lenfname] = '\0'; + ErrorF("OpenFont: fontname is \"%s\"\n", f); + free(f); +#endif + if (!lenfname || lenfname > XLFDMAXFONTNAMELEN) + return BadName; + if (patternCache) { + + /* + ** Check name cache. If we find a cached version of this font that + ** is cachable, immediately satisfy the request with it. If we find + ** a cached version of this font that is non-cachable, we do not + ** satisfy the request with it. Instead, we pass the FontPtr to the + ** FPE's open_font code (the fontfile FPE in turn passes the + ** information to the rasterizer; the fserve FPE ignores it). + ** + ** Presumably, the font is marked non-cachable because the FPE has + ** put some licensing restrictions on it. If the FPE, using + ** whatever logic it relies on, determines that it is willing to + ** share this existing font with the client, then it has the option + ** to return the FontPtr we passed it as the newly-opened font. + ** This allows the FPE to exercise its licensing logic without + ** having to create another instance of a font that already exists. + */ + + cached = FindCachedFontPattern(patternCache, pfontname, lenfname); + if (cached && cached->info.cachable) { + if (!AddResource(fid, RT_FONT, (pointer) cached)) + return BadAlloc; + cached->refcnt++; + return Success; + } + } + c = malloc(sizeof(OFclosureRec)); + if (!c) + return BadAlloc; + c->fontname = malloc(lenfname); + c->origFontName = pfontname; + c->origFontNameLen = lenfname; + if (!c->fontname) { + free(c); + return BadAlloc; + } + /* + * copy the current FPE list, so that if it gets changed by another client + * while we're blocking, the request still appears atomic + */ + c->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c->fontname); + free(c); + return BadAlloc; + } + memmove(c->fontname, pfontname, lenfname); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->fontid = fid; + c->current_fpe = 0; + c->num_fpes = num_fpes; + c->fnamelen = lenfname; + c->slept = FALSE; + c->flags = flags; + c->non_cachable_font = cached; + + (void) doOpenFont(client, c); + return Success; +} + +/** + * Decrement font's ref count, and free storage if ref count equals zero + * + * \param value must conform to DeleteType + */ +_X_EXPORT int +CloseFont(pointer value, XID fid) +{ + int nscr; + + ScreenPtr pscr; + + FontPathElementPtr fpe; + + FontPtr pfont = (FontPtr) value; + + if (pfont == NullFont) + return (Success); + if (--pfont->refcnt == 0) { + if (patternCache) + RemoveCachedFontPattern(patternCache, pfont); + /* + * since the last reference is gone, ask each screen to free any + * storage it may have allocated locally for it. + */ + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + if (pscr->UnrealizeFont) + (*pscr->UnrealizeFont) (pscr, pfont); + } + if (pfont == defaultFont) + defaultFont = NULL; +#ifdef XF86BIGFONT + XF86BigfontFreeFontShm(pfont); +#endif + fpe = pfont->fpe; + (*fpe_functions[fpe->type].close_font) (fpe, pfont); + FreeFPE(fpe); + } + return (Success); +} + +/***====================================================================***/ + +/** + * Sets up pReply as the correct QueryFontReply for pFont with the first + * nProtoCCIStructs char infos. + * + * \param pReply caller must allocate this storage + */ +void +QueryFont(FontPtr pFont, xQueryFontReply * pReply, int nProtoCCIStructs) +{ + FontPropPtr pFP; + + int r, c, i; + + xFontProp *prFP; + + xCharInfo *prCI; + + xCharInfo *charInfos[256]; + + unsigned char chars[512]; + + int ninfos; + + unsigned long ncols; + + unsigned long count; + + /* pr->length set in dispatch */ + pReply->minCharOrByte2 = pFont->info.firstCol; + pReply->defaultChar = pFont->info.defaultCh; + pReply->maxCharOrByte2 = pFont->info.lastCol; + pReply->drawDirection = pFont->info.drawDirection; + pReply->allCharsExist = pFont->info.allExist; + pReply->minByte1 = pFont->info.firstRow; + pReply->maxByte1 = pFont->info.lastRow; + pReply->fontAscent = pFont->info.fontAscent; + pReply->fontDescent = pFont->info.fontDescent; + + pReply->minBounds = pFont->info.ink_minbounds; + pReply->maxBounds = pFont->info.ink_maxbounds; + + pReply->nFontProps = pFont->info.nprops; + pReply->nCharInfos = nProtoCCIStructs; + + for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]); + i < pFont->info.nprops; i++, pFP++, prFP++) { + prFP->name = pFP->name; + prFP->value = pFP->value; + } + + ninfos = 0; + ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1); + prCI = (xCharInfo *) (prFP); + for (r = pFont->info.firstRow; + ninfos < nProtoCCIStructs && r <= (int) pFont->info.lastRow; r++) { + i = 0; + for (c = pFont->info.firstCol; c <= (int) pFont->info.lastCol; c++) { + chars[i++] = r; + chars[i++] = c; + } + (*pFont->get_metrics) (pFont, ncols, chars, + TwoD16Bit, &count, charInfos); + + for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) { + *prCI = *charInfos[i]; + prCI++; + ninfos++; + } + } + return; +} + +static Bool +doListFontsAndAliases(ClientPtr client, LFclosurePtr c) +{ + FontPathElementPtr fpe; + + int err = Successful; + + FontNamesPtr names = NULL; + + char *name, *resolved = NULL; + + int namelen, resolvedlen; + + int nnames; + + int stringLens; + + int i; + + xListFontsReply reply; + + char *bufptr; + + char *bufferStart; + + int aliascount = 0; + + if (client->clientGone) { + if (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } +// err = Successful; + goto bail; + } + + if (!c->current.patlen) + goto finish; + + while (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + + if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) { + /* This FPE doesn't support/require list_fonts_and_aliases */ + + err = (*fpe_functions[fpe->type].list_fonts) + ((pointer) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + c->names); + + if (err == Suspended) { + if (!c->slept) { + c->slept = TRUE; + ClientSleep(client, + (ClientSleepProcPtr) doListFontsAndAliases, + (pointer) c); + } + return TRUE; + } + + err = BadFontName; + } + else { + /* Start of list_fonts_and_aliases functionality. Modeled + after list_fonts_with_info in that it resolves aliases, + except that the information collected from FPEs is just + names, not font info. Each list_next_font_or_alias() + returns either a name into name/namelen or an alias into + name/namelen and its target name into resolved/resolvedlen. + The code at this level then resolves the alias by polling + the FPEs. */ + + if (!c->current.list_started) { + err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) + ((pointer) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + &c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr) doListFontsAndAliases, + (pointer) c); + c->slept = TRUE; + } + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) { + char *tmpname; + + name = 0; + err = (*fpe_functions[fpe->type].list_next_font_or_alias) + ((pointer) c->client, fpe, &name, &namelen, &tmpname, + &resolvedlen, c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr) doListFontsAndAliases, + (pointer) c); + c->slept = TRUE; + } + return TRUE; + } + if (err == FontNameAlias) { + if (resolved) + free(resolved); + resolved = malloc(resolvedlen + 1); + if (resolved) + memmove(resolved, tmpname, resolvedlen + 1); + } + } + + if (err == Successful) { + if (c->haveSaved) { + if (c->savedName) + (void) AddFontNamesName(c->names, c->savedName, + c->savedNameLen); + } + else + (void) AddFontNamesName(c->names, name, namelen); + } + + /* + * When we get an alias back, save our state and reset back to + * the start of the FPE looking for the specified name. As + * soon as a real font is found for the alias, pop back to the + * old state + */ + else if (err == FontNameAlias) { + char tmp_pattern[XLFDMAXFONTNAMELEN]; + + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + memmove(tmp_pattern, resolved, resolvedlen); + if (c->haveSaved) { + char *tmpname; + + int tmpnamelen; + + tmpname = 0; + (void) (*fpe_functions[fpe->type].list_next_font_or_alias) + ((pointer) c->client, fpe, &tmpname, &tmpnamelen, + &tmpname, &tmpnamelen, c->current.private); + if (--aliascount <= 0) { +// err = BadFontName; + goto ContBadFontName; + } + } + else { + c->saved = c->current; + c->haveSaved = TRUE; + if (c->savedName) + free(c->savedName); + c->savedName = malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + c->savedNameLen = namelen; + aliascount = 20; + } + memmove(c->current.pattern, tmp_pattern, resolvedlen); + c->current.patlen = resolvedlen; + c->current.max_names = c->names->nnames + 1; + c->current.current_fpe = -1; + c->current.private = 0; + err = BadFontName; + } + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've collected enough + * font names, quit. + */ + if (err == BadFontName) { + ContBadFontName:; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) { + if (c->names->nnames == c->current.max_names || + c->current.current_fpe == c->num_fpes) { + c->haveSaved = FALSE; + c->current = c->saved; + /* Give the saved namelist a chance to clean itself up */ + continue; + } + } + if (c->names->nnames == c->current.max_names) + break; + } + } + + /* + * send the reply + */ + if (err != Successful) { + SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err)); + goto bail; + } + + finish: + + names = c->names; + nnames = names->nnames; + client = c->client; + stringLens = 0; + for (i = 0; i < nnames; i++) + stringLens += (names->length[i] <= 255) ? names->length[i] : 0; + + reply.type = X_Reply; + reply.length = (stringLens + nnames + 3) >> 2; + reply.nFonts = nnames; + reply.sequenceNumber = client->sequence; + + bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2); + + if (!bufptr && reply.length) { + SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc); + goto bail; + } + /* + * since WriteToClient long word aligns things, copy to temp buffer and + * write all at once + */ + for (i = 0; i < nnames; i++) { + if (names->length[i] > 255) + reply.nFonts--; + else { + *bufptr++ = names->length[i]; + memmove(bufptr, names->names[i], names->length[i]); + bufptr += names->length[i]; + } + } + nnames = reply.nFonts; + reply.length = (stringLens + nnames + 3) >> 2; + client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; + WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); + (void) WriteToClient(client, stringLens + nnames, bufferStart); + DEALLOCATE_LOCAL(bufferStart); + + bail: + if (c->slept) + ClientWakeup(client); + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + if (c->savedName) + free(c->savedName); + FreeFontNames(names); + free(c); + if (resolved) + free(resolved); + return TRUE; +} + +int +ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, + unsigned max_names) +{ + int i; + + LFclosurePtr c; + + /* + * The right error to return here would be BadName, however the + * specification does not allow for a Name error on this request. + * Perhaps a better solution would be to return a nil list, i.e. + * a list containing zero fontnames. + */ + if (length > XLFDMAXFONTNAMELEN) + return BadAlloc; + + if (!(c = malloc(sizeof *c))) + return BadAlloc; + c->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c); + return BadAlloc; + } + c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100); + if (!c->names) { + free(c->fpe_list); + free(c); + return BadAlloc; + } + memmove(c->current.pattern, pattern, length); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->current.patlen = length; + c->current.current_fpe = 0; + c->current.max_names = max_names; + c->current.list_started = FALSE; + c->current.private = 0; + c->haveSaved = FALSE; + c->slept = FALSE; + c->savedName = 0; + doListFontsAndAliases(client, c); + return Success; +} + +int +doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) +{ + FontPathElementPtr fpe; + + int err = Successful; + + char *name; + + int namelen; + + int numFonts; + + FontInfoRec fontInfo, *pFontInfo; + + xListFontsWithInfoReply *reply; + + int length; + + xFontProp *pFP; + + int i; + + int aliascount = 0; + + xListFontsWithInfoReply finalReply; + + if (client->clientGone) { + if (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } + err = Successful; + goto bail; + } + client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo]; + if (!c->current.patlen) + goto finish; + while (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + if (!c->current.list_started) { + err = (*fpe_functions[fpe->type].start_list_fonts_with_info) + (client, fpe, c->current.pattern, c->current.patlen, + c->current.max_names, &c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr) doListFontsWithInfo, c); + c->slept = TRUE; + } + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) { + name = 0; + pFontInfo = &fontInfo; + err = (*fpe_functions[fpe->type].list_next_font_with_info) + (client, fpe, &name, &namelen, &pFontInfo, + &numFonts, c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr) doListFontsWithInfo, c); + c->slept = TRUE; + } + return TRUE; + } + } + /* + * When we get an alias back, save our state and reset back to the + * start of the FPE looking for the specified name. As soon as a real + * font is found for the alias, pop back to the old state + */ + if (err == FontNameAlias) { + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + if (c->haveSaved) { + char *tmpname; + + int tmpnamelen; + + FontInfoPtr tmpFontInfo; + + tmpname = 0; + tmpFontInfo = &fontInfo; + (void) (*fpe_functions[fpe->type].list_next_font_with_info) + (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo, + &numFonts, c->current.private); + if (--aliascount <= 0) { +// err = BadFontName; + goto ContBadFontName; + } + } + else { + c->saved = c->current; + c->haveSaved = TRUE; + c->savedNumFonts = numFonts; + if (c->savedName) + free(c->savedName); + c->savedName = malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + aliascount = 20; + } + memmove(c->current.pattern, name, namelen); + c->current.patlen = namelen; + c->current.max_names = 1; + c->current.current_fpe = 0; + c->current.private = 0; + c->current.list_started = FALSE; + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've sent enough font + * names, quit. Always wait for BadFontName to let the FPE + * have a chance to clean up. + */ + else if (err == BadFontName) { + ContBadFontName:; + c->current.list_started = FALSE; + c->current.current_fpe++; +// err = Successful; + if (c->haveSaved) { + if (c->current.max_names == 0 || + c->current.current_fpe == c->num_fpes) { + c->haveSaved = FALSE; + c->saved.max_names -= (1 - c->current.max_names); + c->current = c->saved; + } + } + else if (c->current.max_names == 0) + break; + } + else if (err == Successful) { + length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp); + reply = c->reply; + if (c->length < length) { + reply = (xListFontsWithInfoReply *) realloc(c->reply, length); + if (!reply) { + err = AllocError; + goto bail; + } + c->reply = reply; + c->length = length; + } + if (c->haveSaved) { + numFonts = c->savedNumFonts; + name = c->savedName; + namelen = strlen(name); + } + reply->type = X_Reply; + reply->length = (sizeof *reply - sizeof(xGenericReply) + + pFontInfo->nprops * sizeof(xFontProp) + + namelen + 3) >> 2; + reply->sequenceNumber = client->sequence; + reply->nameLength = namelen; + reply->minBounds = pFontInfo->ink_minbounds; + reply->maxBounds = pFontInfo->ink_maxbounds; + reply->minCharOrByte2 = pFontInfo->firstCol; + reply->maxCharOrByte2 = pFontInfo->lastCol; + reply->defaultChar = pFontInfo->defaultCh; + reply->nFontProps = pFontInfo->nprops; + reply->drawDirection = pFontInfo->drawDirection; + reply->minByte1 = pFontInfo->firstRow; + reply->maxByte1 = pFontInfo->lastRow; + reply->allCharsExist = pFontInfo->allExist; + reply->fontAscent = pFontInfo->fontAscent; + reply->fontDescent = pFontInfo->fontDescent; + reply->nReplies = numFonts; + pFP = (xFontProp *) (reply + 1); + for (i = 0; i < pFontInfo->nprops; i++) { + pFP->name = pFontInfo->props[i].name; + pFP->value = pFontInfo->props[i].value; + pFP++; + } + WriteSwappedDataToClient(client, length, reply); + (void) WriteToClient(client, namelen, name); + if (pFontInfo == &fontInfo) { + free(fontInfo.props); + free(fontInfo.isStringProp); + } + --c->current.max_names; + } + } + finish: + length = sizeof(xListFontsWithInfoReply); + bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply)); + finalReply.type = X_Reply; + finalReply.sequenceNumber = client->sequence; + finalReply.length = (sizeof(xListFontsWithInfoReply) + - sizeof(xGenericReply)) >> 2; + WriteSwappedDataToClient(client, length, &finalReply); + bail: + if (err == AllocError && c->client != serverClient) { + SendErrorToClient(c->client, X_ListFontsWithInfo, 0, + 0, FontToXError(err)); + } + if (c->slept) + ClientWakeup(client); + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->reply); + free(c->fpe_list); + if (c->savedName) + free(c->savedName); + free(c); + return TRUE; +} + +int +StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, + int max_names) +{ + int i; + + LFWIclosurePtr c; + + /* + * The right error to return here would be BadName, however the + * specification does not allow for a Name error on this request. + * Perhaps a better solution would be to return a nil list, i.e. + * a list containing zero fontnames. + */ + if (length > XLFDMAXFONTNAMELEN) + return BadAlloc; + + if (!(c = malloc(sizeof *c))) + goto badAlloc; + c->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c); + goto badAlloc; + } + memmove(c->current.pattern, pattern, length); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->reply = 0; + c->length = 0; + c->current.patlen = length; + c->current.current_fpe = 0; + c->current.max_names = max_names; + c->current.list_started = FALSE; + c->current.private = 0; + c->savedNumFonts = 0; + c->haveSaved = FALSE; + c->slept = FALSE; + c->savedName = 0; + doListFontsWithInfo(client, c); + return Success; + badAlloc: + return BadAlloc; +} + +#define TextEltHeader 2 +#define FontShiftSize 5 +static XID clearGC[] = { CT_NONE }; + +#define clearGCmask (GCClipMask) + +int +doPolyText(ClientPtr client, register PTclosurePtr c) +{ + FontPtr pFont = c->pGC->font, oldpFont; + + Font fid; + + int err = Success, lgerr; /* err is in X error, not font error, space */ + enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT; + + FontPathElementPtr fpe; + + GC *origGC = NULL; + + if (client->clientGone) { + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + + if (c->slept) { + /* Client has died, but we cannot bail out right now. We + need to clean up after the work we did when going to + sleep. Setting the drawable pointer to 0 makes this + happen without any attempts to render or perform other + unnecessary activities. */ + c->pDraw = (DrawablePtr) 0; + } + else { + err = Success; + goto bail; + } + } + + /* Make sure our drawable hasn't disappeared while we slept. */ + if (c->slept && + c->pDraw && + c->pDraw != (DrawablePtr) SecurityLookupIDByClass(client, c->did, + RC_DRAWABLE, + SecurityWriteAccess)) + { + /* Our drawable has disappeared. Treat like client died... ask + the FPE code to clean up after client and avoid further + rendering while we clean up after ourself. */ + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + c->pDraw = (DrawablePtr) 0; + } + + client_state = c->slept ? SLEEPING : NEVER_SLEPT; + + while (c->endReq - c->pElt > TextEltHeader) { + if (*c->pElt == FontChange) { + + if (c->endReq - c->pElt < FontShiftSize) { + err = BadLength; + goto bail; + } + + oldpFont = pFont; + + fid = ((Font) *(c->pElt + 4)) /* big-endian */ + |((Font) *(c->pElt + 3)) << 8 + | ((Font) *(c->pElt + 2)) << 16 | ((Font) *(c->pElt + 1)) << 24; + pFont = (FontPtr) SecurityLookupIDByType(client, fid, RT_FONT, + SecurityReadAccess); + if (!pFont) { + client->errorValue = fid; + err = BadFont; + /* restore pFont and fid for step 4 (described below) */ + pFont = oldpFont; + + /* If we're in START_SLEEP mode, the following step + shortens the request... in the unlikely event that + the fid somehow becomes valid before we come through + again to actually execute the polytext, which would + then mess up our refcounting scheme badly. */ + c->err = err; + c->endReq = c->pElt; + + goto bail; + } + + /* Step 3 (described below) on our new font */ + if (client_state == START_SLEEP) + pFont->refcnt++; + else { + if (pFont != c->pGC->font && c->pDraw) { + ChangeGC(c->pGC, GCFont, &fid); + ValidateGC(c->pDraw, c->pGC); + if (c->reqType == X_PolyText8) + c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8; + else + c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16; + } + + /* Undo the refcnt++ we performed when going to sleep */ + if (client_state == SLEEPING) + (void) CloseFont(c->pGC->font, (Font) 0); + } + c->pElt += FontShiftSize; + } + else { /* print a string */ + + unsigned char *pNextElt; + + pNextElt = c->pElt + TextEltHeader + (*c->pElt) * c->itemSize; + if (pNextElt > c->endReq) { + err = BadLength; + goto bail; + } + if (client_state == START_SLEEP) { + c->pElt = pNextElt; + continue; + } + if (c->pDraw) { + lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize, + c->pElt + TextEltHeader); + } + else + lgerr = Successful; + + if (lgerr == Suspended) { + if (!c->slept) { + int len; + + GC *pGC; + + PTclosurePtr new_closure; + + /* We're putting the client to sleep. We need to do a few things + to ensure successful and atomic-appearing execution of the + remainder of the request. First, copy the remainder of the + request into a safe malloc'd area. Second, create a scratch GC + to use for the remainder of the request. Third, mark all fonts + referenced in the remainder of the request to prevent their + deallocation. Fourth, make the original GC look like the + request has completed... set its font to the final font value + from this request. These GC manipulations are for the unlikely + (but possible) event that some other client is using the GC. + Steps 3 and 4 are performed by running this procedure through + the remainder of the request in a special no-render mode + indicated by client_state = START_SLEEP. */ + + /* Step 1 */ + /* Allocate a malloc'd closure structure to replace + the local one we were passed */ + new_closure = malloc(sizeof(PTclosureRec)); + if (!new_closure) { + err = BadAlloc; + goto bail; + } + *new_closure = *c; + + len = new_closure->endReq - new_closure->pElt; + new_closure->data = malloc(len); + if (!new_closure->data) { + free(new_closure); + err = BadAlloc; + goto bail; + } + memmove(new_closure->data, new_closure->pElt, len); + new_closure->pElt = new_closure->data; + new_closure->endReq = new_closure->pElt + len; + + /* Step 2 */ + + pGC = GetScratchGC(new_closure->pGC->depth, new_closure->pGC->pScreen); + if (!pGC) { + free(new_closure->data); + free(new_closure); + err = BadAlloc; + goto bail; + } + if ((err = CopyGC(new_closure->pGC, pGC, GCFunction | + GCPlaneMask | GCForeground | + GCBackground | GCFillStyle | + GCTile | GCStipple | + GCTileStipXOrigin | + GCTileStipYOrigin | GCFont | + GCSubwindowMode | GCClipXOrigin | + GCClipYOrigin | GCClipMask)) != Success) { + FreeScratchGC(pGC); + free(new_closure->data); + free(new_closure); + err = BadAlloc; + goto bail; + } + c = new_closure; + origGC = c->pGC; + c->pGC = pGC; + ValidateGC(c->pDraw, c->pGC); + + c->slept = TRUE; + ClientSleep(client, + (ClientSleepProcPtr) doPolyText, (pointer) c); + + /* Set up to perform steps 3 and 4 */ + client_state = START_SLEEP; + continue; /* on to steps 3 and 4 */ + } + return TRUE; + } + else if (lgerr != Successful) { + err = FontToXError(lgerr); + goto bail; + } + if (c->pDraw) { + c->xorg += *((INT8 *) (c->pElt + 1)); /* must be signed */ + c->xorg = (*c->polyText) (c->pDraw, c->pGC, c->xorg, c->yorg, + *c->pElt, c->pElt + TextEltHeader); + } + c->pElt = pNextElt; + } + } + + bail: + + if (client_state == START_SLEEP) { + /* Step 4 */ + if (pFont != origGC->font) { + ChangeGC(origGC, GCFont, &fid); + ValidateGC(c->pDraw, origGC); + } + + /* restore pElt pointer for execution of remainder of the request */ + c->pElt = c->data; + return TRUE; + } + + if (c->err != Success) + err = c->err; + if (err != Success && c->client != serverClient) { + SendErrorToClient(c->client, c->reqType, 0, 0, err); + } + if (c->slept) { + ClientWakeup(c->client); + ChangeGC(c->pGC, clearGCmask, clearGC); + + /* Unreference the font from the scratch GC */ + CloseFont(c->pGC->font, (Font) 0); + c->pGC->font = NullFont; + + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } + return TRUE; +} + +int +PolyText(ClientPtr client, DrawablePtr pDraw, GC * pGC, unsigned char *pElt, + unsigned char *endReq, int xorg, int yorg, int reqType, XID did) +{ + PTclosureRec local_closure; + + local_closure.pElt = pElt; + local_closure.endReq = endReq; + local_closure.client = client; + local_closure.pDraw = pDraw; + local_closure.xorg = xorg; + local_closure.yorg = yorg; + if ((local_closure.reqType = reqType) == X_PolyText8) { + local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8; + local_closure.itemSize = 1; + } + else { + local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText16; + local_closure.itemSize = 2; + } + local_closure.pGC = pGC; + local_closure.did = did; + local_closure.err = Success; + local_closure.slept = FALSE; + + (void) doPolyText(client, &local_closure); + return Success; +} + +#undef TextEltHeader +#undef FontShiftSize + +int +doImageText(ClientPtr client, register ITclosurePtr c) +{ + int err = Success, lgerr; /* err is in X error, not font error, space */ + + FontPathElementPtr fpe; + + if (client->clientGone) { + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + err = Success; + goto bail; + } + + /* Make sure our drawable hasn't disappeared while we slept. */ + if (c->slept && + c->pDraw && + c->pDraw != (DrawablePtr) SecurityLookupIDByClass(client, c->did, + RC_DRAWABLE, + SecurityWriteAccess)) + { + /* Our drawable has disappeared. Treat like client died... ask + the FPE code to clean up after client. */ + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + err = Success; + goto bail; + } + + lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data); + if (lgerr == Suspended) { + if (!c->slept) { + GC *pGC; + + unsigned char *data; + + ITclosurePtr new_closure; + ITclosurePtr old_closure; + + /* We're putting the client to sleep. We need to + save some state. Similar problem to that handled + in doPolyText, but much simpler because the + request structure is much simpler. */ + + new_closure = malloc(sizeof(ITclosureRec)); + if (!new_closure) { + err = BadAlloc; + goto bail; + } + old_closure = c; + *new_closure = *c; + c = new_closure; + + data = malloc(c->nChars * c->itemSize); + if (!data) { + free(c); + c = old_closure; + err = BadAlloc; + goto bail; + } + memmove(data, c->data, c->nChars * c->itemSize); + c->data = data; + + pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); + if (!pGC) { + free(c->data); + free(c); + c = old_closure; + err = BadAlloc; + goto bail; + } + if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask | + GCForeground | GCBackground | GCFillStyle | + GCTile | GCStipple | GCTileStipXOrigin | + GCTileStipYOrigin | GCFont | + GCSubwindowMode | GCClipXOrigin | + GCClipYOrigin | GCClipMask)) != Success) { + FreeScratchGC(pGC); + free(c->data); + free(c); + c = old_closure; + err = BadAlloc; + goto bail; + } + c->pGC = pGC; + ValidateGC(c->pDraw, c->pGC); + + c->slept = TRUE; + ClientSleep(client, (ClientSleepProcPtr) doImageText, (pointer) c); + } + return TRUE; + } + else if (lgerr != Successful) { + err = FontToXError(lgerr); + goto bail; + } + if (c->pDraw) { + (*c->imageText) (c->pDraw, c->pGC, c->xorg, c->yorg, + c->nChars, c->data); + } + + bail: + + if (err != Success && c->client != serverClient) { + SendErrorToClient(c->client, c->reqType, 0, 0, err); + } + if (c->slept) { + ClientWakeup(c->client); + ChangeGC(c->pGC, clearGCmask, clearGC); + + /* Unreference the font from the scratch GC */ + CloseFont(c->pGC->font, (Font) 0); + c->pGC->font = NullFont; + + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } + return TRUE; +} + +int +ImageText(ClientPtr client, DrawablePtr pDraw, GC * pGC, int nChars, + unsigned char *data, int xorg, int yorg, int reqType, XID did) +{ + ITclosureRec local_closure; + + local_closure.client = client; + local_closure.pDraw = pDraw; + local_closure.pGC = pGC; + local_closure.nChars = nChars; + local_closure.data = data; + local_closure.xorg = xorg; + local_closure.yorg = yorg; + if ((local_closure.reqType = reqType) == X_ImageText8) { + local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8; + local_closure.itemSize = 1; + } + else { + local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16; + local_closure.itemSize = 2; + } + local_closure.did = did; + local_closure.slept = FALSE; + + (void) doImageText(client, &local_closure); + return Success; +} + +/* does the necessary magic to figure out the fpe type */ +static int +DetermineFPEType(char *pathname) +{ + int i; + + for (i = 0; i < num_fpe_types; i++) { + if ((*fpe_functions[i].name_check) (pathname)) + return i; + } + return -1; +} + +static void +FreeFontPath(FontPathElementPtr * list, int n, Bool force) +{ + int i; + + for (i = 0; i < n; i++) { + if (force) { + /* Sanity check that all refcounts will be 0 by the time + we get to the end of the list. */ + int found = 1; /* the first reference is us */ + + int j; + + for (j = i + 1; j < n; j++) { + if (list[j] == list[i]) + found++; + } + if (list[i]->refcount != found) { + list[i]->refcount = found; /* ensure it will get freed */ + } + } + FreeFPE(list[i]); + } + free((char *) list); +} + +static FontPathElementPtr +find_existing_fpe(FontPathElementPtr * list, int num, unsigned char *name, + int len) +{ + FontPathElementPtr fpe; + + int i; + + for (i = 0; i < num; i++) { + fpe = list[i]; + if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0) + return fpe; + } + return (FontPathElementPtr) 0; +} + +static int +SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist) +{ + int i, err = 0; + + int valid_paths = 0; + + unsigned int len; + + unsigned char *cp = paths; + + FontPathElementPtr fpe = NULL, *fplist; + + fplist = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * npaths); + if (!fplist) { + *bad = 0; + return BadAlloc; + } + for (i = 0; i < num_fpe_types; i++) { + if (fpe_functions[i].set_path_hook) + (*fpe_functions[i].set_path_hook) (); + } + for (i = 0; i < npaths; i++) { + len = (unsigned int) (*cp++); + + if (len == 0) { + if (persist) + ErrorF + ("Removing empty element from the valid list of fontpaths\n"); + err = BadValue; + } + else { + /* if it's already in our active list, just reset it */ + /* + * note that this can miss FPE's in limbo -- may be worth catching + * them, though it'd muck up refcounting + */ + fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len); + if (fpe) { + err = (*fpe_functions[fpe->type].reset_fpe) (fpe); + if (err == Successful) { + UseFPE(fpe); /* since it'll be decref'd later when freed + * from the old list */ + } + else + fpe = 0; + } + /* if error or can't do it, act like it's a new one */ + if (!fpe) { + fpe = malloc(sizeof(FontPathElementRec)); + if (!fpe) { + err = BadAlloc; + goto bail; + } + fpe->name = malloc(len + 1); + if (!fpe->name) { + free(fpe); + err = BadAlloc; + goto bail; + } + fpe->refcount = 1; + + strncpy(fpe->name, (char *) cp, (int) len); + fpe->name[len] = '\0'; + fpe->name_length = len; + fpe->type = DetermineFPEType(fpe->name); + if (fpe->type == -1) + err = BadValue; + else + err = (*fpe_functions[fpe->type].init_fpe) (fpe); + if (err != Successful) { + if (persist) { + ErrorF + ("Could not init font path element %s, removing from list!\n", + fpe->name); + } + free(fpe->name); + free(fpe); + } + } + } + if (err != Successful) { + if (!persist) + goto bail; + } + else { + fplist[valid_paths++] = fpe; + } + cp += len; + } + + FreeFontPath(font_path_elements, num_fpes, FALSE); + font_path_elements = fplist; + if (patternCache) + EmptyFontPatternCache(patternCache); + num_fpes = valid_paths; + + return Success; + bail: + *bad = i; + while (--valid_paths >= 0) + FreeFPE(fplist[valid_paths]); + free(fplist); + return FontToXError(err); +} + +/* XXX -- do we need to pass error down to each renderer? */ +int +SetFontPath(ClientPtr client, int npaths, unsigned char *paths, int *error) +{ + int err = Success; + + if (npaths == 0) { + if (SetDefaultFontPath(defaultFontPath) != Success) + return BadValue; + } + else { + err = SetFontPathElements(npaths, paths, error, FALSE); + } + return err; +} + +int +SetDefaultFontPath(char *path) +{ + unsigned char *cp, *pp, *nump, *newpath; + + int num = 1, len, err, size = 0, bad; + + /* get enough for string, plus values -- use up commas */ + len = strlen(path) + 1; + nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len); + if (!newpath) + return BadAlloc; + pp = (unsigned char *) path; + cp++; + while (*pp) { + if (*pp == ',') { + *nump = (unsigned char) size; + nump = cp++; + pp++; + num++; + size = 0; + } + else { + *cp++ = *pp++; + size++; + } + } + *nump = (unsigned char) size; + + err = SetFontPathElements(num, newpath, &bad, TRUE); + + DEALLOCATE_LOCAL(newpath); + + return err; +} + +unsigned char * +GetFontPath(int *count, int *length) +{ + int i; + + unsigned char *c; + + int len; + + FontPathElementPtr fpe; + + len = 0; + for (i = 0; i < num_fpes; i++) { + fpe = font_path_elements[i]; + len += fpe->name_length + 1; + } + font_path_string = (unsigned char *) realloc(font_path_string, len); + if (!font_path_string) + return NULL; + + c = font_path_string; + *length = 0; + for (i = 0; i < num_fpes; i++) { + fpe = font_path_elements[i]; + *c = fpe->name_length; + *length += *c++; + memmove(c, fpe->name, fpe->name_length); + c += fpe->name_length; + } + *count = num_fpes; + return font_path_string; +} + +_X_EXPORT int +LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, + unsigned char *data) +{ + if (fpe_functions[pfont->fpe->type].load_glyphs) + return (*fpe_functions[pfont->fpe->type].load_glyphs) + (client, pfont, 0, nchars, item_size, data); + else + return Successful; +} + +void +DeleteClientFontStuff(ClientPtr client) +{ + int i; + + FontPathElementPtr fpe; + + for (i = 0; i < num_fpes; i++) { + fpe = font_path_elements[i]; + if (fpe_functions[fpe->type].client_died) + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } +} + +void +InitFonts() +{ + patternCache = MakeFontPatternCache(); + + { +#ifdef KDRIVESERVER + BuiltinRegisterFpeFunctions(); +#endif + FontFileRegisterFpeFunctions(); + } +} + +_X_EXPORT +int +GetDefaultPointSize() +{ + return 120; +} + +_X_EXPORT +FontResolutionPtr +GetClientResolutions(int *num) +{ + if (requestingClient && requestingClient->fontResFunc != NULL && + !requestingClient->clientGone) { + return (*requestingClient->fontResFunc) (requestingClient, num); + } + else { + static struct _FontResolution res; + + ScreenPtr pScreen; + + pScreen = screenInfo.screens[0]; + res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; + /* + * XXX - we'll want this as long as bitmap instances are prevalent + so that we can match them from scalable fonts + */ + if (res.x_resolution < 88) + res.x_resolution = 75; + else + res.x_resolution = 100; + res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; + if (res.y_resolution < 88) + res.y_resolution = 75; + else + res.y_resolution = 100; + res.point_size = 120; + *num = 1; + return &res; + } +} + +/* + * returns the type index of the new fpe + * + * should be called (only once!) by each type of fpe when initialized + */ + +_X_EXPORT +int +RegisterFPEFunctions(NameCheckFunc name_func, + InitFpeFunc init_func, + FreeFpeFunc free_func, + ResetFpeFunc reset_func, + OpenFontFunc open_func, + CloseFontFunc close_func, + ListFontsFunc list_func, + StartLfwiFunc start_lfwi_func, + NextLfwiFunc next_lfwi_func, + WakeupFpeFunc wakeup_func, + ClientDiedFunc client_died, + LoadGlyphsFunc load_glyphs, + StartLaFunc start_list_alias_func, + NextLaFunc next_list_alias_func, SetPathFunc set_path_func) +{ + FPEFunctions *new; + + /* grow the list */ + new = (FPEFunctions *) realloc(fpe_functions, + (num_fpe_types + 1) * sizeof(FPEFunctions)); + if (!new) + return -1; + fpe_functions = new; + + fpe_functions[num_fpe_types].name_check = name_func; + fpe_functions[num_fpe_types].open_font = open_func; + fpe_functions[num_fpe_types].close_font = close_func; + fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func; + fpe_functions[num_fpe_types].list_fonts = list_func; + fpe_functions[num_fpe_types].start_list_fonts_with_info = start_lfwi_func; + fpe_functions[num_fpe_types].list_next_font_with_info = next_lfwi_func; + fpe_functions[num_fpe_types].init_fpe = init_func; + fpe_functions[num_fpe_types].free_fpe = free_func; + fpe_functions[num_fpe_types].reset_fpe = reset_func; + fpe_functions[num_fpe_types].client_died = client_died; + fpe_functions[num_fpe_types].load_glyphs = load_glyphs; + fpe_functions[num_fpe_types].start_list_fonts_and_aliases = + start_list_alias_func; + fpe_functions[num_fpe_types].list_next_font_or_alias = next_list_alias_func; + fpe_functions[num_fpe_types].set_path_hook = set_path_func; + + return num_fpe_types++; +} + +void +FreeFonts() +{ + if (patternCache) { + FreeFontPatternCache(patternCache); + patternCache = 0; + } + FreeFontPath(font_path_elements, num_fpes, TRUE); + font_path_elements = 0; + num_fpes = 0; + free(fpe_functions); + num_fpe_types = 0; + fpe_functions = (FPEFunctions *) 0; +} + +/* convenience functions for FS interface */ + +FontPtr +find_old_font(XID id) +{ + return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE, + SecurityUnknownAccess); +} + +_X_EXPORT +Font +GetNewFontClientID() +{ + return FakeClientID(0); +} + +_X_EXPORT +int +StoreFontClientFont(FontPtr pfont, Font id) +{ + return AddResource(id, RT_NONE, (pointer) pfont); +} + +_X_EXPORT +void +DeleteFontClientID(Font id) +{ + FreeResource(id, RT_NONE); +} + +_X_EXPORT +int +client_auth_generation(ClientPtr client) +{ + return 0; +} + +static int fs_handlers_installed = 0; + +static unsigned int last_server_gen; + +_X_EXPORT +int +init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler) +{ + /* if server has reset, make sure the b&w handlers are reinstalled */ + if (last_server_gen < serverGeneration) { + last_server_gen = serverGeneration; + fs_handlers_installed = 0; + } + if (fs_handlers_installed == 0) { + + + if (!RegisterBlockAndWakeupHandlers(block_handler, + FontWakeup, (pointer) 0)) + return AllocError; + fs_handlers_installed++; + } + QueueFontWakeup(fpe); + return Successful; +} + +_X_EXPORT +void +remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, + Bool all) +{ + if (all) { + /* remove the handlers if no one else is using them */ + if (--fs_handlers_installed == 0) { + + + RemoveBlockAndWakeupHandlers(block_handler, FontWakeup, + (pointer) 0); + } + } + RemoveFontWakeup(fpe); +} + diff --git a/dix/dixutils.c b/dix/dixutils.c new file mode 100644 index 0000000..17faa93 --- /dev/null +++ b/dix/dixutils.c @@ -0,0 +1,837 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + +(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved. + +Permission to use, copy, modify, distribute, and sublicense this software and its +documentation for any purpose and without fee is hereby granted, provided that +the above copyright notices appear in all copies and that both those copyright +notices and this permission notice appear in supporting documentation and that +the name of Adobe Systems Incorporated not be used in advertising or publicity +pertaining to distribution of the software without specific, written prior +permission. No trademark license to use the Adobe trademarks is hereby +granted. If the Adobe trademark "Display PostScript"(tm) is used to describe +this software, its functionality or for any other purpose, such use shall be +limited to a statement that this software works in conjunction with the Display +PostScript system. Proper trademark attribution to reflect Adobe's ownership +of the trademark shall be given whenever any such reference to the Display +PostScript system is made. + +ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY +PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON- +INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU +OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT +LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER +SUPPORT FOR THE SOFTWARE. + +Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems +Incorporated which may be registered in certain jurisdictions. + +Author: Adobe Systems Incorporated + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "windowstr.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#define XK_LATIN1 +#include + +/* + * CompareTimeStamps returns -1, 0, or +1 depending on if the first + * argument is less than, equal to or greater than the second argument. + */ + +_X_EXPORT int +CompareTimeStamps(TimeStamp a, TimeStamp b) +{ + if (a.months < b.months) + return EARLIER; + if (a.months > b.months) + return LATER; + if (a.milliseconds < b.milliseconds) + return EARLIER; + if (a.milliseconds > b.milliseconds) + return LATER; + return SAMETIME; +} + +/* + * convert client times to server TimeStamps + */ + +#define HALFMONTH ((unsigned long) 1<<31) +_X_EXPORT TimeStamp +ClientTimeToServerTime(CARD32 c) +{ + TimeStamp ts; + + if (c == CurrentTime) + return currentTime; + ts.months = currentTime.months; + ts.milliseconds = c; + if (c > currentTime.milliseconds) { + if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) + ts.months -= 1; + } + else if (c < currentTime.milliseconds) { + if (((unsigned long) currentTime.milliseconds - c) > HALFMONTH) + ts.months += 1; + } + return ts; +} + +/* + * ISO Latin-1 case conversion routine + * + * this routine always null-terminates the result, so + * beware of too-small buffers + */ + +static unsigned char +ISOLatin1ToLower(unsigned char source) +{ + unsigned char dest; + + if ((source >= XK_A) && (source <= XK_Z)) + dest = source + (XK_a - XK_A); + else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) + dest = source + (XK_agrave - XK_Agrave); + else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) + dest = source + (XK_oslash - XK_Ooblique); + else + dest = source; + return dest; +} + +int +CompareISOLatin1Lowered(unsigned char *s1, int s1len, + unsigned char *s2, int s2len) +{ + unsigned char c1, c2; + + for (;;) { + /* note -- compare against zero so that -1 ignores len */ + c1 = s1len-- ? *s1++ : '\0'; + c2 = s2len-- ? *s2++ : '\0'; + if (!c1 || + (c1 != c2 && + (c1 = ISOLatin1ToLower(c1)) != (c2 = ISOLatin1ToLower(c2)))) + break; + } + return (int) c1 - (int) c2; +} + + +WindowPtr +LookupWindow(XID rid, ClientPtr client) +{ + WindowPtr pWin; + + client->errorValue = rid; + if (rid == INVALID) + return NULL; + if (client->lastDrawableID == rid) { + if (client->lastDrawable->type == DRAWABLE_WINDOW) + return ((WindowPtr) client->lastDrawable); + return (WindowPtr) NULL; + } + pWin = (WindowPtr) LookupIDByType(rid, RT_WINDOW); + if (pWin && pWin->drawable.type == DRAWABLE_WINDOW) { + client->lastDrawable = (DrawablePtr) pWin; + client->lastDrawableID = rid; + client->lastGCID = INVALID; + client->lastGC = (GCPtr) NULL; + } + return pWin; +} + +pointer +LookupDrawable(XID rid, ClientPtr client) +{ + DrawablePtr pDraw; + + if (rid == INVALID) + return (pointer) NULL; + if (client->lastDrawableID == rid) + return ((pointer) client->lastDrawable); + pDraw = (DrawablePtr) LookupIDByClass(rid, RC_DRAWABLE); + if (pDraw && (pDraw->type != UNDRAWABLE_WINDOW)) + return (pointer) pDraw; + return (pointer) NULL; +} + + +_X_EXPORT ClientPtr +LookupClient(XID rid, ClientPtr client) +{ + pointer pRes = (pointer) SecurityLookupIDByClass(client, rid, RC_ANY, + SecurityReadAccess); + + int clientIndex = CLIENT_ID(rid); + + if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) { + return clients[clientIndex]; + } + return (ClientPtr) NULL; +} + +int +AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, + Bool toRoot, Bool remap) +{ + int numnow; + + SaveSetElt *pTmp = NULL; + + int j; + + numnow = client->numSaved; + j = 0; + if (numnow) { + pTmp = client->saveSet; + while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer) pWin)) + j++; + } + if (mode == SetModeInsert) { + if (j < numnow) /* duplicate */ + return (Success); + numnow++; + pTmp = (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow); + if (!pTmp) + return (BadAlloc); + client->saveSet = pTmp; + client->numSaved = numnow; + SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); + SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); + SaveSetAssignRemap(client->saveSet[numnow - 1], remap); + return (Success); + } + else if ((mode == SetModeDelete) && (j < numnow)) { + while (j < numnow - 1) { + pTmp[j] = pTmp[j + 1]; + j++; + } + numnow--; + if (numnow) { + pTmp = + (SaveSetElt *) realloc(client->saveSet, + sizeof(*pTmp) * numnow); + if (pTmp) + client->saveSet = pTmp; + } + else { + free(client->saveSet); + client->saveSet = (SaveSetElt *) NULL; + } + client->numSaved = numnow; + return (Success); + } + return (Success); +} + +void +DeleteWindowFromAnySaveSet(WindowPtr pWin) +{ + int i; + + ClientPtr client; + + for (i = 0; i < currentMaxClients; i++) { + client = clients[i]; + if (client && client->numSaved) + (void) AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, + TRUE); + } +} + +/* No-op Don't Do Anything : sometimes we need to be able to call a procedure + * that doesn't do anything. For example, on screen with only static + * colormaps, if someone calls install colormap, it's easier to have a dummy + * procedure to call than to check if there's a procedure + */ +_X_EXPORT void +NoopDDA(void) +{ +} + +typedef struct _BlockHandler { + BlockHandlerProcPtr BlockHandler; + WakeupHandlerProcPtr WakeupHandler; + pointer blockData; + Bool deleted; +} BlockHandlerRec, *BlockHandlerPtr; + +static BlockHandlerPtr handlers; + +static int numHandlers; + +static int sizeHandlers; + +static Bool inHandler; + +static Bool handlerDeleted; + +/** + * + * \param pTimeout DIX doesn't want to know how OS represents time + * \param pReadMask nor how it represents the det of descriptors + */ +void +BlockHandler(pointer pTimeout, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = 0; i < screenInfo.numScreens; i++) + (*screenInfo.screens[i]->BlockHandler) (i, + screenInfo.screens[i]-> + blockData, pTimeout, pReadmask); + for (i = 0; i < numHandlers; i++) + (*handlers[i].BlockHandler) (handlers[i].blockData, + pTimeout, pReadmask); + if (handlerDeleted) { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j + 1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * + * \param result 32 bits of undefined result from the wait + * \param pReadmask the resulting descriptor mask + */ +void +WakeupHandler(int result, pointer pReadmask) +{ + int i, j; + + ++inHandler; + for (i = numHandlers - 1; i >= 0; i--) + (*handlers[i].WakeupHandler) (handlers[i].blockData, result, pReadmask); + for (i = 0; i < screenInfo.numScreens; i++) + (*screenInfo.screens[i]->WakeupHandler) (i, + screenInfo.screens[i]-> + wakeupData, result, pReadmask); + if (handlerDeleted) { + for (i = 0; i < numHandlers;) + if (handlers[i].deleted) { + for (j = i; j < numHandlers - 1; j++) + handlers[j] = handlers[j + 1]; + numHandlers--; + } + else + i++; + handlerDeleted = FALSE; + } + --inHandler; +} + +/** + * Reentrant with BlockHandler and WakeupHandler, except wakeup won't + * get called until next time + */ +_X_EXPORT Bool +RegisterBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + BlockHandlerPtr new; + + if (numHandlers >= sizeHandlers) { + new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * + sizeof(BlockHandlerRec)); + if (!new) + return FALSE; + handlers = new; + sizeHandlers = numHandlers + 1; + } + handlers[numHandlers].BlockHandler = blockHandler; + handlers[numHandlers].WakeupHandler = wakeupHandler; + handlers[numHandlers].blockData = blockData; + handlers[numHandlers].deleted = FALSE; + numHandlers = numHandlers + 1; + return TRUE; +} + +_X_EXPORT void +RemoveBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler, + WakeupHandlerProcPtr wakeupHandler, + pointer blockData) +{ + int i; + + for (i = 0; i < numHandlers; i++) + if (handlers[i].BlockHandler == blockHandler && + handlers[i].WakeupHandler == wakeupHandler && + handlers[i].blockData == blockData) { + if (inHandler) { + handlerDeleted = TRUE; + handlers[i].deleted = TRUE; + } + else { + for (; i < numHandlers - 1; i++) + handlers[i] = handlers[i + 1]; + numHandlers--; + } + break; + } +} + +void +InitBlockAndWakeupHandlers() +{ + free(handlers); + handlers = (BlockHandlerPtr) 0; + numHandlers = 0; + sizeHandlers = 0; +} + +/* + * A general work queue. Perform some task before the server + * sleeps for input. + */ + +WorkQueuePtr workQueue; + +static WorkQueuePtr *workQueueLast = &workQueue; + +void +ProcessWorkQueue(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + /* + * Scan the work queue once, calling each function. Those + * which return TRUE are removed from the queue, otherwise + * they will be called again. This must be reentrant with + * QueueWorkProc. + */ + while ((q = *p)) { + if ((*q->function) (q->client, q->closure)) { + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + free(q); + } + else { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +void +ProcessWorkQueueZombies(void) +{ + WorkQueuePtr q, *p; + + p = &workQueue; + while ((q = *p)) { + if (q->client && q->client->clientGone) { + (void) (*q->function) (q->client, q->closure); + /* remove q from the list */ + *p = q->next; /* don't fetch until after func called */ + free(q); + } + else { + p = &q->next; /* don't fetch until after func called */ + } + } + workQueueLast = p; +} + +_X_EXPORT Bool +QueueWorkProc(Bool (*function) + (ClientPtr /* pClient */ , pointer /* closure */ ), + ClientPtr client, pointer closure) +{ + WorkQueuePtr q; + + q = malloc(sizeof *q); + if (!q) + return FALSE; + q->function = function; + q->client = client; + q->closure = closure; + q->next = NULL; + *workQueueLast = q; + workQueueLast = &q->next; + return TRUE; +} + +/* + * Manage a queue of sleeping clients, awakening them + * when requested, by using the OS functions IgnoreClient + * and AttendClient. Note that this *ignores* the troubles + * with request data interleaving itself with events, but + * we'll leave that until a later time. + */ + +typedef struct _SleepQueue { + struct _SleepQueue *next; + ClientPtr client; + ClientSleepProcPtr function; + pointer closure; +} SleepQueueRec, *SleepQueuePtr; + +static SleepQueuePtr sleepQueue = NULL; + +_X_EXPORT Bool +ClientSleep(ClientPtr client, ClientSleepProcPtr function, pointer closure) +{ + SleepQueuePtr q; + + q = malloc(sizeof *q); + if (!q) + return FALSE; + + IgnoreClient(client); + q->next = sleepQueue; + q->client = client; + q->function = function; + q->closure = closure; + sleepQueue = q; + return TRUE; +} + +Bool +ClientSignal(ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) { + return QueueWorkProc(q->function, q->client, q->closure); + } + return FALSE; +} + +_X_EXPORT void +ClientWakeup(ClientPtr client) +{ + SleepQueuePtr q, *prev; + + prev = &sleepQueue; + while ((q = *prev)) { + if (q->client == client) { + *prev = q->next; + free(q); + if (client->clientGone) + /* Oops -- new zombie cleanup code ensures this only + * happens from inside CloseDownClient; don't want to + * recurse here... + */ + /* CloseDownClient(client) */ ; + else + AttendClient(client); + break; + } + prev = &q->next; + } +} + +Bool +ClientIsAsleep(ClientPtr client) +{ + SleepQueuePtr q; + + for (q = sleepQueue; q; q = q->next) + if (q->client == client) + return TRUE; + return FALSE; +} + +/* + * Generic Callback Manager + */ + +/* ===== Private Procedures ===== */ + +static int numCallbackListsToCleanup = 0; + +static CallbackListPtr **listsToCleanup = NULL; + +static Bool +_AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + CallbackPtr cbr; + + cbr = malloc(sizeof(CallbackRec)); + if (!cbr) + return FALSE; + cbr->proc = callback; + cbr->data = data; + cbr->next = (*pcbl)->list; + cbr->deleted = FALSE; + (*pcbl)->list = cbr; + return TRUE; +} + +static Bool +_DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + CallbackListPtr cbl = *pcbl; + + CallbackPtr cbr, pcbr; + + for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) { + if ((cbr->proc == callback) && (cbr->data == data)) + break; + } + if (cbr != NULL) { + if (cbl->inCallback) { + ++(cbl->numDeleted); + cbr->deleted = TRUE; + } + else { + if (pcbr == NULL) + cbl->list = cbr->next; + else + pcbr->next = cbr->next; + free(cbr); + } + return TRUE; + } + return FALSE; +} + +static void +_CallCallbacks(CallbackListPtr *pcbl, pointer call_data) +{ + CallbackListPtr cbl = *pcbl; + + CallbackPtr cbr, pcbr; + + ++(cbl->inCallback); + for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) { + (*(cbr->proc)) (pcbl, cbr->data, call_data); + } + --(cbl->inCallback); + + if (cbl->inCallback) + return; + + /* Was the entire list marked for deletion? */ + + if (cbl->deleted) { + DeleteCallbackList(pcbl); + return; + } + + /* Were some individual callbacks on the list marked for deletion? + * If so, do the deletions. + */ + + if (cbl->numDeleted) { + for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) { + if (cbr->deleted) { + if (pcbr) { + cbr = cbr->next; + free(pcbr->next); + pcbr->next = cbr; + } + else { + cbr = cbr->next; + free(cbl->list); + cbl->list = cbr; + } + cbl->numDeleted--; + } + else { /* this one wasn't deleted */ + + pcbr = cbr; + cbr = cbr->next; + } + } + } +} + +static void +_DeleteCallbackList(CallbackListPtr *pcbl) +{ + CallbackListPtr cbl = *pcbl; + + CallbackPtr cbr, nextcbr; + + int i; + + if (cbl->inCallback) { + cbl->deleted = TRUE; + return; + } + + for (i = 0; i < numCallbackListsToCleanup; i++) { + if ((listsToCleanup[i] = pcbl) != 0) { + listsToCleanup[i] = NULL; + break; + } + } + + for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) { + nextcbr = cbr->next; + free(cbr); + } + free(cbl); + *pcbl = NULL; +} + +static CallbackFuncsRec default_cbfuncs = { + _AddCallback, + _DeleteCallback, + _CallCallbacks, + _DeleteCallbackList +}; + +/* ===== Public Procedures ===== */ + +Bool +CreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs) +{ + CallbackListPtr cbl; + + int i; + + if (!pcbl) + return FALSE; + cbl = malloc(sizeof(CallbackListRec)); + if (!cbl) + return FALSE; + cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs; + cbl->inCallback = 0; + cbl->deleted = FALSE; + cbl->numDeleted = 0; + cbl->list = NULL; + *pcbl = cbl; + + for (i = 0; i < numCallbackListsToCleanup; i++) { + if (!listsToCleanup[i]) { + listsToCleanup[i] = pcbl; + return TRUE; + } + } + + listsToCleanup = (CallbackListPtr **) realloc(listsToCleanup, + sizeof(CallbackListPtr *) * + (numCallbackListsToCleanup + + 1)); + listsToCleanup[numCallbackListsToCleanup] = pcbl; + numCallbackListsToCleanup++; + return TRUE; +} + +_X_EXPORT Bool +AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl) + return FALSE; + if (!*pcbl) { /* list hasn't been created yet; go create it */ + if (!CreateCallbackList(pcbl, (CallbackFuncsPtr) NULL)) + return FALSE; + } + return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data)); +} + +_X_EXPORT Bool +DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) +{ + if (!pcbl || !*pcbl) + return FALSE; + return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data)); +} + +void +CallCallbacks(CallbackListPtr *pcbl, pointer call_data) +{ + if (!pcbl || !*pcbl) + return; + (*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data); +} + +void +DeleteCallbackList(CallbackListPtr *pcbl) +{ + if (!pcbl || !*pcbl) + return; + (*(*pcbl)->funcs.DeleteCallbackList) (pcbl); +} + +void +InitCallbackManager() +{ + int i; + + for (i = 0; i < numCallbackListsToCleanup; i++) { + DeleteCallbackList(listsToCleanup[i]); + } + if (listsToCleanup) + free(listsToCleanup); + + numCallbackListsToCleanup = 0; + listsToCleanup = NULL; +} diff --git a/dix/events.c b/dix/events.c new file mode 100644 index 0000000..9cf8172 --- /dev/null +++ b/dix/events.c @@ -0,0 +1,3437 @@ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/***************************************************************** + +Copyright 2003-2005 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL +INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "resource.h" +#include +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" + +#include "dixstruct.h" +#include "globals.h" + + + + +#include +#include "exevents.h" +#include "extnsionst.h" + +#include "dixevents.h" +#include "dixgrabs.h" +#include "dispatch.h" + +#define EXTENSION_EVENT_BASE 64 + +#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ +#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) +#define AllButtonsMask ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) +#define MotionMask ( \ + PointerMotionMask | Button1MotionMask | \ + Button2MotionMask | Button3MotionMask | Button4MotionMask | \ + Button5MotionMask | ButtonMotionMask ) +#define PropagateMask ( \ + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ + MotionMask ) +#define PointerGrabMask ( \ + ButtonPressMask | ButtonReleaseMask | \ + EnterWindowMask | LeaveWindowMask | \ + PointerMotionHintMask | KeymapStateMask | \ + MotionMask ) +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) +#define AllEventMasks (lastEventMask|(lastEventMask-1)) +/* + * The following relies on the fact that the ButtonMotionMasks are equal + * to the corresponding ButtonMasks from the current modifier/button state. + */ +#define Motion_Filter(class) (PointerMotionMask | \ + (class)->state | (class)->motionMask) + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) + +#define XE_KBPTR (xE->u.keyButtonPointer) + +#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) + +_X_EXPORT CallbackListPtr EventCallback; + +_X_EXPORT CallbackListPtr DeviceEventCallback; + +#define DNPMCOUNT 8 + +Mask DontPropagateMasks[DNPMCOUNT]; + +static int DontPropagateRefCnts[DNPMCOUNT]; + +#ifdef DEBUG +static debug_events = 0; +#endif +_X_EXPORT InputInfo inputInfo; + +static struct { + QdEventPtr pending, *pendtail; + DeviceIntPtr replayDev; /* kludgy rock to put flag for */ + WindowPtr replayWin; /* ComputeFreezes */ + Bool playingEvents; + TimeStamp time; +} syncEvents; + +/* + * The window trace information is used to avoid having to compute all the + * windows between the root and the current pointer window each time a button + * or key goes down. The grabs on each of those windows must be checked. + */ +static WindowPtr *spriteTrace = (WindowPtr *) NULL; + +#define ROOT spriteTrace[0] +static int spriteTraceSize = 0; + +static int spriteTraceGood; + +static struct { + CursorPtr current; + BoxRec hotLimits; /* logical constraints of hot spot */ + Bool confined; /* confined to screen */ + RegionPtr hotShape; /* additional logical shape constraint */ + BoxRec physLimits; /* physical constraints of hot spot */ + WindowPtr win; /* window of logical position */ + HotSpot hot; /* logical pointer position */ + HotSpot hotPhys; /* physical pointer position */ +} sprite; /* info about the cursor sprite */ + + +static void DoEnterLeaveEvents(WindowPtr fromWin, WindowPtr toWin, int mode); + +static WindowPtr XYToWindow(int x, int y); + +extern int lastEvent; + +static Mask lastEventMask; + + +#define CantBeFiltered NoEventMask +static Mask filters[128]; + +static const Mask initialFilters[128] = { + NoSuchEvent, /* 0 */ + NoSuchEvent, /* 1 */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask, /* MotionNotify (initial state) */ + EnterWindowMask, /* EnterNotify */ + LeaveWindowMask, /* LeaveNotify */ + FocusChangeMask, /* FocusIn */ + FocusChangeMask, /* FocusOut */ + KeymapStateMask, /* KeymapNotify */ + ExposureMask, /* Expose */ + CantBeFiltered, /* GraphicsExpose */ + CantBeFiltered, /* NoExpose */ + VisibilityChangeMask, /* VisibilityNotify */ + SubstructureNotifyMask, /* CreateNotify */ + StructureAndSubMask, /* DestroyNotify */ + StructureAndSubMask, /* UnmapNotify */ + StructureAndSubMask, /* MapNotify */ + SubstructureRedirectMask, /* MapRequest */ + StructureAndSubMask, /* ReparentNotify */ + StructureAndSubMask, /* ConfigureNotify */ + SubstructureRedirectMask, /* ConfigureRequest */ + StructureAndSubMask, /* GravityNotify */ + ResizeRedirectMask, /* ResizeRequest */ + StructureAndSubMask, /* CirculateNotify */ + SubstructureRedirectMask, /* CirculateRequest */ + PropertyChangeMask, /* PropertyNotify */ + CantBeFiltered, /* SelectionClear */ + CantBeFiltered, /* SelectionRequest */ + CantBeFiltered, /* SelectionNotify */ + ColormapChangeMask, /* ColormapNotify */ + CantBeFiltered, /* ClientMessage */ + CantBeFiltered /* MappingNotify */ +}; + +static CARD8 criticalEvents[32] = { + 0x7c /* key and button events */ +}; + + +void +SetMaskForEvent(Mask mask, int event) +{ + if ((event < LASTEvent) || (event >= 128)) + FatalError("SetMaskForEvent: bogus event number"); + filters[event] = mask; +} + +_X_EXPORT void +SetCriticalEvent(int event) +{ + if (event >= 128) + FatalError("SetCriticalEvent: bogus event number"); + criticalEvents[event >> 3] |= 1 << (event & 7); +} + +static void +SyntheticMotion(int x, int y) +{ + xEvent xE; + + xE.u.keyButtonPointer.rootX = x; + xE.u.keyButtonPointer.rootY = y; + if (syncEvents.playingEvents) + xE.u.keyButtonPointer.time = syncEvents.time.milliseconds; + else + xE.u.keyButtonPointer.time = currentTime.milliseconds; + xE.u.u.type = MotionNotify; + (*inputInfo.pointer->public.processInputProc) (&xE, inputInfo.pointer, 1); +} + +static void +ConfineToShape(RegionPtr shape, int *px, int *py) +{ + BoxRec box; + + int x = *px, y = *py; + + int incx = 1, incy = 1; + + if (POINT_IN_REGION(shape, x, y, &box)) + return; + box = *REGION_EXTENTS(shape); + /* this is rather crude */ + do { + x += incx; + if (x >= box.x2) { + incx = -1; + x = *px - 1; + } + else if (x < box.x1) { + incx = 1; + x = *px; + y += incy; + if (y >= box.y2) { + incy = -1; + y = *py - 1; + } + else if (y < box.y1) + return; /* should never get here! */ + } + } while (!POINT_IN_REGION(shape, x, y, &box)); + *px = x; + *py = y; +} + +static void +CheckPhysLimits(CursorPtr cursor, + Bool generateEvents, Bool confineToScreen, ScreenPtr pScreen) +{ + HotSpot new; + + if (!cursor) + return; + new = sprite.hotPhys; + if (pScreen) + new.pScreen = pScreen; + else + pScreen = new.pScreen; + (*pScreen->CursorLimits) (pScreen, cursor, &sprite.hotLimits, + &sprite.physLimits); + sprite.confined = confineToScreen; + (*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits); + if (new.x < sprite.physLimits.x1) + new.x = sprite.physLimits.x1; + else if (new.x >= sprite.physLimits.x2) + new.x = sprite.physLimits.x2 - 1; + if (new.y < sprite.physLimits.y1) + new.y = sprite.physLimits.y1; + else if (new.y >= sprite.physLimits.y2) + new.y = sprite.physLimits.y2 - 1; + if (sprite.hotShape) + ConfineToShape(sprite.hotShape, &new.x, &new.y); + if ((pScreen != sprite.hotPhys.pScreen) || + (new.x != sprite.hotPhys.x) || (new.y != sprite.hotPhys.y)) { + if (pScreen != sprite.hotPhys.pScreen) + sprite.hotPhys = new; + (*pScreen->SetCursorPosition) (pScreen, new.x, new.y, generateEvents); + if (!generateEvents) + SyntheticMotion(new.x, new.y); + } +} + +static void +CheckVirtualMotion(register QdEventPtr qe, register WindowPtr pWin) +{ + if (qe) { + sprite.hot.pScreen = qe->pScreen; + sprite.hot.x = qe->event->u.keyButtonPointer.rootX; + sprite.hot.y = qe->event->u.keyButtonPointer.rootY; + pWin = inputInfo.pointer->grab ? inputInfo.pointer->grab->confineTo : + NullWindow; + } + if (pWin) { + BoxRec lims; + + if (sprite.hot.pScreen != pWin->drawable.pScreen) { + sprite.hot.pScreen = pWin->drawable.pScreen; + sprite.hot.x = sprite.hot.y = 0; + } + lims = *REGION_EXTENTS(&pWin->borderSize); + if (sprite.hot.x < lims.x1) + sprite.hot.x = lims.x1; + else if (sprite.hot.x >= lims.x2) + sprite.hot.x = lims.x2 - 1; + if (sprite.hot.y < lims.y1) + sprite.hot.y = lims.y1; + else if (sprite.hot.y >= lims.y2) + sprite.hot.y = lims.y2 - 1; + if (wBoundingShape(pWin)) + ConfineToShape(&pWin->borderSize, &sprite.hot.x, &sprite.hot.y); + if (qe) { + qe->pScreen = sprite.hot.pScreen; + qe->event->u.keyButtonPointer.rootX = sprite.hot.x; + qe->event->u.keyButtonPointer.rootY = sprite.hot.y; + } + } + ROOT = WindowTable[sprite.hot.pScreen->myNum]; +} + +static void +ConfineCursorToWindow(WindowPtr pWin, Bool generateEvents, Bool confineToScreen) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + + if (syncEvents.playingEvents) { + CheckVirtualMotion((QdEventPtr) NULL, pWin); + SyntheticMotion(sprite.hot.x, sprite.hot.y); + } + else { + sprite.hotLimits = *REGION_EXTENTS(&pWin->borderSize); + sprite.hotShape = wBoundingShape(pWin) ? &pWin->borderSize : NullRegion; + CheckPhysLimits(sprite.current, generateEvents, confineToScreen, + pScreen); + } +} + +_X_EXPORT Bool +PointerConfinedToScreen() +{ + return sprite.confined; +} + +static void +ChangeToCursor(CursorPtr cursor) +{ + + if (cursor != sprite.current) { + if ((sprite.current->bits->xhot != cursor->bits->xhot) || + (sprite.current->bits->yhot != cursor->bits->yhot)) + CheckPhysLimits(cursor, FALSE, sprite.confined, (ScreenPtr) NULL); + (*sprite.hotPhys.pScreen->DisplayCursor) (sprite.hotPhys.pScreen, + cursor); + FreeCursor(sprite.current, (Cursor) 0); + sprite.current = cursor; + sprite.current->refcnt++; + } +} + +/* returns true if b is a descendent of a */ +Bool +IsParent(register WindowPtr a, register WindowPtr b) +{ + for (b = b->parent; b; b = b->parent) + if (b == a) + return TRUE; + return FALSE; +} + +static void +PostNewCursor(void) +{ + WindowPtr win; + + GrabPtr grab = inputInfo.pointer->grab; + + if (syncEvents.playingEvents) + return; + if (grab) { + if (grab->cursor) { + ChangeToCursor(grab->cursor); + return; + } + if (IsParent(grab->window, sprite.win)) + win = sprite.win; + else + win = grab->window; + } + else + win = sprite.win; + for (; win; win = win->parent) + if (win->optional && win->optional->cursor != NullCursor) { + ChangeToCursor(win->optional->cursor); + return; + } +} + +_X_EXPORT WindowPtr +GetCurrentRootWindow() +{ + return ROOT; +} + +_X_EXPORT WindowPtr +GetSpriteWindow() +{ + return sprite.win; +} + +_X_EXPORT CursorPtr +GetSpriteCursor() +{ + return sprite.current; +} + +_X_EXPORT void +GetSpritePosition(int *px, int *py) +{ + *px = sprite.hotPhys.x; + *py = sprite.hotPhys.y; +} + + +#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ + +static void +MonthChangedOrBadTime(register xEvent *xE) +{ + /* If the ddx/OS is careless about not processing timestamped events from + * different sources in sorted order, then it's possible for time to go + * backwards when it should not. Here we ensure a decent time. + */ + if ((currentTime.milliseconds - XE_KBPTR.time) > TIMESLOP) + currentTime.months++; + else + XE_KBPTR.time = currentTime.milliseconds; +} + +#define NoticeTime(xE) { \ + if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \ + MonthChangedOrBadTime(xE); \ + currentTime.milliseconds = (xE)->u.keyButtonPointer.time; \ + lastDeviceEventTime = currentTime; } + +void +NoticeEventTime(register xEvent *xE) +{ + if (!syncEvents.playingEvents) + NoticeTime(xE); +} + +/************************************************************************** + * The following procedures deal with synchronous events * + **************************************************************************/ + +void +EnqueueEvent(xEvent *xE, DeviceIntPtr device, int count) +{ + QdEventPtr tail = *syncEvents.pendtail; + + QdEventPtr qe; + + xEvent *qxE; + + NoticeTime(xE); + + + if (DeviceEventCallback) { + DeviceEventInfoRec eventinfo; + + /* The RECORD spec says that the root window field of motion events + * must be valid. At this point, it hasn't been filled in yet, so + * we do it here. The long expression below is necessary to get + * the current root window; the apparently reasonable alternative + * GetCurrentRootWindow()->drawable.id doesn't give you the right + * answer on the first motion event after a screen change because + * the data that GetCurrentRootWindow relies on hasn't been + * updated yet. + */ + if (xE->u.u.type == MotionNotify) + XE_KBPTR.root = + WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id; + eventinfo.events = xE; + eventinfo.count = count; + CallCallbacks(&DeviceEventCallback, (pointer) &eventinfo); + } + if (xE->u.u.type == MotionNotify) { + sprite.hotPhys.x = XE_KBPTR.rootX; + sprite.hotPhys.y = XE_KBPTR.rootY; + /* do motion compression */ + if (tail && + (tail->event->u.u.type == MotionNotify) && + (tail->pScreen == sprite.hotPhys.pScreen)) { + tail->event->u.keyButtonPointer.rootX = sprite.hotPhys.x; + tail->event->u.keyButtonPointer.rootY = sprite.hotPhys.y; + tail->event->u.keyButtonPointer.time = XE_KBPTR.time; + tail->months = currentTime.months; + return; + } + } + qe = malloc(sizeof(QdEventRec) + (count * sizeof(xEvent))); + if (!qe) + return; + qe->next = (QdEventPtr) NULL; + qe->device = device; + qe->pScreen = sprite.hotPhys.pScreen; + qe->months = currentTime.months; + qe->event = (xEvent *) (qe + 1); + qe->evcount = count; + for (qxE = qe->event; --count >= 0; qxE++, xE++) + *qxE = *xE; + if (tail) + syncEvents.pendtail = &tail->next; + *syncEvents.pendtail = qe; +} + +static void +PlayReleasedEvents(void) +{ + QdEventPtr *prev, qe; + + DeviceIntPtr dev; + + prev = &syncEvents.pending; + while ((qe = *prev)) { + if (!qe->device->sync.frozen) { + *prev = qe->next; + if (*syncEvents.pendtail == *prev) + syncEvents.pendtail = prev; + if (qe->event->u.u.type == MotionNotify) + CheckVirtualMotion(qe, NullWindow); + syncEvents.time.months = qe->months; + syncEvents.time.milliseconds = qe->event->u.keyButtonPointer.time; + (*qe->device->public.processInputProc) (qe->event, qe->device, + qe->evcount); + free(qe); + for (dev = inputInfo.devices; dev && dev->sync.frozen; + dev = dev->next); + if (!dev) + break; + /* Playing the event may have unfrozen another device. */ + /* So to play it safe, restart at the head of the queue */ + prev = &syncEvents.pending; + } + else + prev = &qe->next; + } +} + +static void +FreezeThaw(register DeviceIntPtr dev, Bool frozen) +{ + dev->sync.frozen = frozen; + if (frozen) + dev->public.processInputProc = dev->public.enqueueInputProc; + else + dev->public.processInputProc = dev->public.realInputProc; +} + +void +ComputeFreezes() +{ + DeviceIntPtr replayDev = syncEvents.replayDev; + + int i; + + WindowPtr w; + + xEvent *xE; + + int count; + + GrabPtr grab; + + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + FreezeThaw(dev, dev->sync.other || (dev->sync.state >= FROZEN)); + if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) + return; + syncEvents.playingEvents = TRUE; + if (replayDev) { + xE = replayDev->sync.event; + count = replayDev->sync.evcount; + syncEvents.replayDev = (DeviceIntPtr) NULL; + + w = XYToWindow(XE_KBPTR.rootX, XE_KBPTR.rootY); + for (i = 0; i < spriteTraceGood; i++) { + if (syncEvents.replayWin == spriteTrace[i]) { + if (!CheckDeviceGrabs(replayDev, xE, i + 1, count)) { + if (replayDev->focus) + DeliverFocusedEvent(replayDev, xE, w, count); + else + DeliverDeviceEvents(w, xE, NullGrab, NullWindow, + replayDev, count); + } + goto playmore; + } + } + /* must not still be in the same stack */ + if (replayDev->focus) + DeliverFocusedEvent(replayDev, xE, w, count); + else + DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count); + } + playmore: + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (!dev->sync.frozen) { + PlayReleasedEvents(); + break; + } + } + syncEvents.playingEvents = FALSE; + /* the following may have been skipped during replay, so do it now */ + if ((grab = inputInfo.pointer->grab) &&grab->confineTo) { + if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) + sprite.hotPhys.x = sprite.hotPhys.y = 0; + ConfineCursorToWindow(grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], + TRUE, FALSE); + PostNewCursor(); +} + +void +ScreenRestructured(ScreenPtr pScreen) +{ + GrabPtr grab; + + if ((grab = inputInfo.pointer->grab) &&grab->confineTo) { + if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) + sprite.hotPhys.x = sprite.hotPhys.y = 0; + ConfineCursorToWindow(grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum], + TRUE, FALSE); +} + +void +CheckGrabForSyncs(register DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) +{ + GrabPtr grab = thisDev->grab; + + DeviceIntPtr dev; + + if (thisMode == GrabModeSync) + thisDev->sync.state = FROZEN_NO_EVENT; + else { /* free both if same client owns both */ + thisDev->sync.state = THAWED; + if (thisDev->sync.other && + (CLIENT_BITS(thisDev->sync.other->resource) == + CLIENT_BITS(grab->resource))) + thisDev->sync.other = NullGrab; + } + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev != thisDev) { + if (otherMode == GrabModeSync) + dev->sync.other = grab; + else { /* free both if same client owns both */ + if (dev->sync.other && + (CLIENT_BITS(dev->sync.other->resource) == + CLIENT_BITS(grab->resource))) + dev->sync.other = NullGrab; + } + } + } + ComputeFreezes(); +} + +void +ActivatePointerGrab(register DeviceIntPtr mouse, register GrabPtr grab, + TimeStamp time, Bool autoGrab) +{ + WindowPtr oldWin = (mouse->grab) ? mouse->grab->window : sprite.win; + + if (grab->confineTo) { + if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) + sprite.hotPhys.x = sprite.hotPhys.y = 0; + ConfineCursorToWindow(grab->confineTo, FALSE, TRUE); + } + DoEnterLeaveEvents(oldWin, grab->window, NotifyGrab); + mouse->valuator->motionHintWindow = NullWindow; + if (syncEvents.playingEvents) + mouse->grabTime = syncEvents.time; + else + mouse->grabTime = time; + if (grab->cursor) + grab->cursor->refcnt++; + mouse->activeGrab = *grab; + mouse->grab = &mouse->activeGrab; + mouse->fromPassiveGrab = autoGrab; + PostNewCursor(); + CheckGrabForSyncs(mouse, (Bool) grab->pointerMode, + (Bool) grab->keyboardMode); +} + +void +DeactivatePointerGrab(register DeviceIntPtr mouse) +{ + GrabPtr grab = mouse->grab; + + DeviceIntPtr dev; + + mouse->valuator->motionHintWindow = NullWindow; + mouse->grab = NullGrab; + mouse->sync.state = NOT_GRABBED; + mouse->fromPassiveGrab = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->sync.other == grab) + dev->sync.other = NullGrab; + } + DoEnterLeaveEvents(grab->window, sprite.win, NotifyUngrab); + if (grab->confineTo) + ConfineCursorToWindow(ROOT, FALSE, FALSE); + PostNewCursor(); + if (grab->cursor) + FreeCursor(grab->cursor, (Cursor) 0); + ComputeFreezes(); +} + +void +ActivateKeyboardGrab(register DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, + Bool passive) +{ + WindowPtr oldWin; + + if (keybd->grab) + oldWin = keybd->grab->window; + else if (keybd->focus) + oldWin = keybd->focus->win; + else + oldWin = sprite.win; + if (oldWin == FollowKeyboardWin) + oldWin = inputInfo.keyboard->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); + if (syncEvents.playingEvents) + keybd->grabTime = syncEvents.time; + else + keybd->grabTime = time; + keybd->activeGrab = *grab; + keybd->grab = &keybd->activeGrab; + keybd->fromPassiveGrab = passive; + CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode, + (Bool) grab->pointerMode); +} + +void +DeactivateKeyboardGrab(register DeviceIntPtr keybd) +{ + GrabPtr grab = keybd->grab; + + DeviceIntPtr dev; + + WindowPtr focusWin = keybd->focus ? keybd->focus->win : sprite.win; + + if (focusWin == FollowKeyboardWin) + focusWin = inputInfo.keyboard->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + keybd->grab = NullGrab; + keybd->sync.state = NOT_GRABBED; + keybd->fromPassiveGrab = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->sync.other == grab) + dev->sync.other = NullGrab; + } + DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); + ComputeFreezes(); +} + +void +AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState) +{ + Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; + + TimeStamp grabTime; + + DeviceIntPtr dev; + + thisGrabbed = thisDev->grab && SameClient(thisDev->grab, client); + thisSynced = FALSE; + otherGrabbed = FALSE; + othersFrozen = TRUE; + grabTime = thisDev->grabTime; + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev == thisDev) + continue; + if (dev->grab && SameClient(dev->grab, client)) { + if (!(thisGrabbed || otherGrabbed) || + (CompareTimeStamps(dev->grabTime, grabTime) == LATER)) + grabTime = dev->grabTime; + otherGrabbed = TRUE; + if (thisDev->sync.other == dev->grab) + thisSynced = TRUE; + if (dev->sync.state < FROZEN) + othersFrozen = FALSE; + } + else if (!dev->sync.other || !SameClient(dev->sync.other, client)) + othersFrozen = FALSE; + } + if (!((thisGrabbed && thisDev->sync.state >= FROZEN) || thisSynced)) + return; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabTime) == EARLIER)) + return; + switch (newState) { + case THAWED: /* Async */ + if (thisGrabbed) + thisDev->sync.state = THAWED; + if (thisSynced) + thisDev->sync.other = NullGrab; + ComputeFreezes(); + break; + case FREEZE_NEXT_EVENT: /* Sync */ + if (thisGrabbed) { + thisDev->sync.state = FREEZE_NEXT_EVENT; + if (thisSynced) + thisDev->sync.other = NullGrab; + ComputeFreezes(); + } + break; + case THAWED_BOTH: /* AsyncBoth */ + if (othersFrozen) { + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->grab && SameClient(dev->grab, client)) + dev->sync.state = THAWED; + if (dev->sync.other && SameClient(dev->sync.other, client)) + dev->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ + if (othersFrozen) { + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->grab && SameClient(dev->grab, client)) + dev->sync.state = FREEZE_BOTH_NEXT_EVENT; + if (dev->sync.other && SameClient(dev->sync.other, client)) + dev->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case NOT_GRABBED: /* Replay */ + if (thisGrabbed && thisDev->sync.state == FROZEN_WITH_EVENT) { + if (thisSynced) + thisDev->sync.other = NullGrab; + syncEvents.replayDev = thisDev; + syncEvents.replayWin = thisDev->grab->window; + (*thisDev->DeactivateGrab) (thisDev); + syncEvents.replayDev = (DeviceIntPtr) NULL; + } + break; + case THAW_OTHERS: /* AsyncOthers */ + if (othersFrozen) { + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev == thisDev) + continue; + if (dev->grab && SameClient(dev->grab, client)) + dev->sync.state = THAWED; + if (dev->sync.other && SameClient(dev->sync.other, client)) + dev->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + } +} + +int +ProcAllowEvents(register ClientPtr client) +{ + TimeStamp time; + + DeviceIntPtr mouse = inputInfo.pointer; + + DeviceIntPtr keybd = inputInfo.keyboard; + + REQUEST(xAllowEventsReq); + + REQUEST_SIZE_MATCH(xAllowEventsReq); + time = ClientTimeToServerTime(stuff->time); + switch (stuff->mode) { + case ReplayPointer: + AllowSome(client, time, mouse, NOT_GRABBED); + break; + case SyncPointer: + AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); + break; + case AsyncPointer: + AllowSome(client, time, mouse, THAWED); + break; + case ReplayKeyboard: + AllowSome(client, time, keybd, NOT_GRABBED); + break; + case SyncKeyboard: + AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); + break; + case AsyncKeyboard: + AllowSome(client, time, keybd, THAWED); + break; + case SyncBoth: + AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); + break; + case AsyncBoth: + AllowSome(client, time, keybd, THAWED_BOTH); + break; + default: + client->errorValue = stuff->mode; + return BadValue; + } + return Success; +} + +void +ReleaseActiveGrabs(ClientPtr client) +{ + DeviceIntPtr dev; + + Bool done; + + /* XXX CloseDownClient should remove passive grabs before + * releasing active grabs. + */ + do { + done = TRUE; + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev->grab && SameClient(dev->grab, client)) { + (*dev->DeactivateGrab) (dev); + done = FALSE; + } + } + } while (!done); +} + +/************************************************************************** + * The following procedures deal with delivering events * + **************************************************************************/ + +_X_EXPORT int +TryClientEvents(ClientPtr client, xEvent *pEvents, int count, Mask mask, + Mask filter, GrabPtr grab) +{ + int i; + + int type; + +#ifdef DEBUG + if (debug_events) + ErrorF("Event([%d, %d], mask=0x%x), client=%d", + pEvents->u.u.type, pEvents->u.u.detail, mask, client->index); +#endif + if ((client) && (client != serverClient) && (!client->clientGone) && + ((filter == CantBeFiltered) || (mask & filter))) { + if (grab && !SameClient(grab, client)) + return -1; /* don't send, but notify caller */ + type = pEvents->u.u.type; + if (type == MotionNotify) { + if (mask & PointerMotionHintMask) { + if (WID(inputInfo.pointer->valuator->motionHintWindow) == + pEvents->u.keyButtonPointer.event) { +#ifdef DEBUG + if (debug_events) + ErrorF("\n"); + fprintf(stderr, + "motionHintWindow == keyButtonPointer.event\n"); +#endif + return 1; /* don't send, but pretend we did */ + } + pEvents->u.u.detail = NotifyHint; + } + else { + pEvents->u.u.detail = NotifyNormal; + } + } + type &= 0177; + if (type != KeymapNotify) { + /* all extension events must have a sequence number */ + for (i = 0; i < count; i++) + pEvents[i].u.u.sequenceNumber = client->sequence; + } + + if (BitIsOn(criticalEvents, type)) { +#ifdef SMART_SCHEDULE + if (client->smart_priority < SMART_MAX_PRIORITY) + client->smart_priority++; +#endif + SetCriticalOutputPending(); + } + + WriteEventsToClient(client, count, pEvents); +#ifdef DEBUG + if (debug_events) + ErrorF(" delivered\n"); +#endif + return 1; + } + else { +#ifdef DEBUG + if (debug_events) + ErrorF("\n"); +#endif + return 0; + } +} + +int +DeliverEventsToWindow(register WindowPtr pWin, xEvent *pEvents, int count, + Mask filter, GrabPtr grab, int mskidx) +{ + int deliveries = 0, nondeliveries = 0; + + int attempt; + + InputClients *other; + + ClientPtr client = NullClient; + + Mask deliveryMask = 0; /* If a grab occurs due to a button press, then + this mask is the mask of the grab. */ + int type = pEvents->u.u.type; + + /* CantBeFiltered means only window owner gets the event */ + if ((filter == CantBeFiltered) || !(type & EXTENSION_EVENT_BASE)) { + /* if nobody ever wants to see this event, skip some work */ + if (filter != CantBeFiltered && + !((wOtherEventMasks(pWin) | pWin->eventMask) & filter)) + return 0; + if ((attempt = TryClientEvents(wClient(pWin), pEvents, count, + pWin->eventMask, filter, grab))) { + if (attempt > 0) { + deliveries++; + client = wClient(pWin); + deliveryMask = pWin->eventMask; + } + else + nondeliveries--; + } + } + if (filter != CantBeFiltered) { + if (type & EXTENSION_EVENT_BASE) { + OtherInputMasks *inputMasks; + + inputMasks = wOtherInputMasks(pWin); + if (!inputMasks || !(inputMasks->inputEvents[mskidx] & filter)) + return 0; + other = inputMasks->inputClients; + } + else + other = (InputClients *) wOtherClients(pWin); + for (; other; other = other->next) { + if ((attempt = TryClientEvents(rClient(other), pEvents, count, + other->mask[mskidx], filter, grab))) + { + if (attempt > 0) { + deliveries++; + client = rClient(other); + deliveryMask = other->mask[mskidx]; + } + else + nondeliveries--; + } + } + } + if ((type == ButtonPress) && deliveries && (!grab)) { + GrabRec tempGrab; + + tempGrab.device = inputInfo.pointer; + + tempGrab.resource = client->clientAsMask; + tempGrab.window = pWin; + tempGrab.ownerEvents = + (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; + tempGrab.eventMask = deliveryMask; + tempGrab.keyboardMode = GrabModeAsync; + tempGrab.pointerMode = GrabModeAsync; + tempGrab.confineTo = NullWindow; + tempGrab.cursor = NullCursor; + (*inputInfo.pointer->ActivateGrab) (inputInfo.pointer, &tempGrab, + currentTime, TRUE); + } + else if ((type == MotionNotify) && deliveries) + inputInfo.pointer->valuator->motionHintWindow = pWin; + + if (deliveries) + return deliveries; + return nondeliveries; +} + +/* If the event goes to dontClient, don't send it and return 0. if + send works, return 1 or if send didn't work, return 2. + Only works for core events. +*/ + + +int +MaybeDeliverEventsToClient(register WindowPtr pWin, xEvent *pEvents, + int count, Mask filter, ClientPtr dontClient) +{ + OtherClients *other; + + if (pWin->eventMask & filter) { + if (wClient(pWin) == dontClient) + return 0; + return TryClientEvents(wClient(pWin), pEvents, count, + pWin->eventMask, filter, NullGrab); + } + for (other = wOtherClients(pWin); other; other = other->next) { + if (other->mask & filter) { + if (SameClient(other, dontClient)) + return 0; + return TryClientEvents(rClient(other), pEvents, count, + other->mask, filter, NullGrab); + } + } + return 2; +} + +static void +FixUpEventFromWindow(xEvent *xE, WindowPtr pWin, Window child, Bool calcChild) +{ + if (calcChild) { + WindowPtr w = spriteTrace[spriteTraceGood - 1]; + + /* If the search ends up past the root should the child field be + set to none or should the value in the argument be passed + through. It probably doesn't matter since everyone calls + this function with child == None anyway. */ + + while (w) { + /* If the source window is same as event window, child should be + none. Don't bother going all all the way back to the root. */ + + if (w == pWin) { + child = None; + break; + } + + if (w->parent == pWin) { + child = w->drawable.id; + break; + } + w = w->parent; + } + } + XE_KBPTR.root = ROOT->drawable.id; + XE_KBPTR.event = pWin->drawable.id; + if (sprite.hot.pScreen == pWin->drawable.pScreen) { + XE_KBPTR.sameScreen = xTrue; + XE_KBPTR.child = child; + XE_KBPTR.eventX = XE_KBPTR.rootX - pWin->drawable.x; + XE_KBPTR.eventY = XE_KBPTR.rootY - pWin->drawable.y; + } + else { + XE_KBPTR.sameScreen = xFalse; + XE_KBPTR.child = None; + XE_KBPTR.eventX = 0; + XE_KBPTR.eventY = 0; + } +} + +int +DeliverDeviceEvents(register WindowPtr pWin, register xEvent *xE, GrabPtr grab, + register WindowPtr stopAt, DeviceIntPtr dev, int count) +{ + Window child = None; + + int type = xE->u.u.type; + + Mask filter = filters[type]; + + int deliveries = 0; + + if (type & EXTENSION_EVENT_BASE) { + OtherInputMasks *inputMasks; + + int mskidx = dev->id; + + inputMasks = wOtherInputMasks(pWin); + if (inputMasks && !(filter & inputMasks->deliverableEvents[mskidx])) + return 0; + while (pWin) { + if (inputMasks && (inputMasks->inputEvents[mskidx] & filter)) { + FixUpEventFromWindow(xE, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(pWin, xE, count, filter, + grab, mskidx); + if (deliveries > 0) + return deliveries; + } + if ((deliveries < 0) || + (pWin == stopAt) || + (inputMasks && + (filter & inputMasks->dontPropagateMask[mskidx]))) + return 0; + child = pWin->drawable.id; + pWin = pWin->parent; + if (pWin) + inputMasks = wOtherInputMasks(pWin); + } + } + else { + if (!(filter & pWin->deliverableEvents)) + return 0; + while (pWin) { + if ((wOtherEventMasks(pWin) | pWin->eventMask) & filter) { + FixUpEventFromWindow(xE, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(pWin, xE, count, filter, + grab, 0); + if (deliveries > 0) + return deliveries; + } + if ((deliveries < 0) || + (pWin == stopAt) || (filter & wDontPropagateMask(pWin))) + return 0; + child = pWin->drawable.id; + pWin = pWin->parent; + } + } + return 0; +} + +/* not useful for events that propagate up the tree or extension events */ +_X_EXPORT int +DeliverEvents(register WindowPtr pWin, register xEvent *xE, int count, + register WindowPtr otherParent) +{ + Mask filter; + + int deliveries; + + + if (!count) + return 0; + filter = filters[xE->u.u.type]; + if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) + xE->u.destroyNotify.event = pWin->drawable.id; + if (filter != StructureAndSubMask) + return DeliverEventsToWindow(pWin, xE, count, filter, NullGrab, 0); + deliveries = DeliverEventsToWindow(pWin, xE, count, StructureNotifyMask, + NullGrab, 0); + if (pWin->parent) { + xE->u.destroyNotify.event = pWin->parent->drawable.id; + deliveries += DeliverEventsToWindow(pWin->parent, xE, count, + SubstructureNotifyMask, NullGrab, + 0); + if (xE->u.u.type == ReparentNotify) { + xE->u.destroyNotify.event = otherParent->drawable.id; + deliveries += DeliverEventsToWindow(otherParent, xE, count, + SubstructureNotifyMask, + NullGrab, 0); + } + } + return deliveries; +} + +static Bool +PointInBorderSize(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if (POINT_IN_REGION(&pWin->borderSize, x, y, &box)) + return TRUE; + + return FALSE; +} + +static WindowPtr +XYToWindow(int x, int y) +{ + WindowPtr pWin; + + BoxRec box; + + spriteTraceGood = 1; /* root window still there */ + pWin = ROOT->firstChild; + while (pWin) { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth(pWin)) && + (x < pWin->drawable.x + (int) pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth(pWin)) && + (y < pWin->drawable.y + (int) pWin->drawable.height + + wBorderWidth(pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) + && (!wInputShape(pWin) || + POINT_IN_REGION( + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) + ) { + if (spriteTraceGood >= spriteTraceSize) { + spriteTraceSize += 10; + Must_have_memory = TRUE; /* XXX */ + spriteTrace = + (WindowPtr *) realloc(spriteTrace, + spriteTraceSize * sizeof(WindowPtr)); + Must_have_memory = FALSE; /* XXX */ + } + spriteTrace[spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return spriteTrace[spriteTraceGood - 1]; +} + +static Bool +CheckMotion(xEvent *xE) +{ + WindowPtr prevSpriteWin = sprite.win; + + + if (xE && !syncEvents.playingEvents) { + if (sprite.hot.pScreen != sprite.hotPhys.pScreen) { + sprite.hot.pScreen = sprite.hotPhys.pScreen; + ROOT = WindowTable[sprite.hot.pScreen->myNum]; + } + sprite.hot.x = XE_KBPTR.rootX; + sprite.hot.y = XE_KBPTR.rootY; + if (sprite.hot.x < sprite.physLimits.x1) + sprite.hot.x = sprite.physLimits.x1; + else if (sprite.hot.x >= sprite.physLimits.x2) + sprite.hot.x = sprite.physLimits.x2 - 1; + if (sprite.hot.y < sprite.physLimits.y1) + sprite.hot.y = sprite.physLimits.y1; + else if (sprite.hot.y >= sprite.physLimits.y2) + sprite.hot.y = sprite.physLimits.y2 - 1; + if (sprite.hotShape) + ConfineToShape(sprite.hotShape, &sprite.hot.x, &sprite.hot.y); + sprite.hotPhys = sprite.hot; + if ((sprite.hotPhys.x != XE_KBPTR.rootX) || + (sprite.hotPhys.y != XE_KBPTR.rootY)) { + (*sprite.hotPhys.pScreen->SetCursorPosition) (sprite.hotPhys. + pScreen, + sprite.hotPhys.x, + sprite.hotPhys.y, + FALSE); + } + XE_KBPTR.rootX = sprite.hot.x; + XE_KBPTR.rootY = sprite.hot.y; + } + + sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); +#ifdef notyet + if (!(sprite.win->deliverableEvents & + Motion_Filter(inputInfo.pointer->button)) + ! syncEvents.playingEvents) { + /* XXX Do PointerNonInterestBox here */ + } +#endif + if (sprite.win != prevSpriteWin) { + if (prevSpriteWin != NullWindow) { + if (!xE) + UpdateCurrentTimeIf(); + DoEnterLeaveEvents(prevSpriteWin, sprite.win, NotifyNormal); + } + PostNewCursor(); + return FALSE; + } + return TRUE; +} + +_X_EXPORT void +WindowsRestructured() +{ + (void) CheckMotion((xEvent *) NULL); +} + + +void +DefineInitialRootWindow(register WindowPtr win) +{ + ScreenPtr pScreen = win->drawable.pScreen; + + sprite.hotPhys.pScreen = pScreen; + sprite.hotPhys.x = pScreen->width / 2; + sprite.hotPhys.y = pScreen->height / 2; + sprite.hot = sprite.hotPhys; + sprite.hotLimits.x2 = pScreen->width; + sprite.hotLimits.y2 = pScreen->height; + sprite.win = win; + sprite.current = wCursor(win); + sprite.current->refcnt++; + spriteTraceGood = 1; + ROOT = win; + (*pScreen->CursorLimits) (pScreen, sprite.current, &sprite.hotLimits, + &sprite.physLimits); + sprite.confined = FALSE; + (*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits); + (*pScreen->SetCursorPosition) (pScreen, sprite.hot.x, sprite.hot.y, FALSE); + (*pScreen->DisplayCursor) (pScreen, sprite.current); + +} + +/* + * This does not take any shortcuts, and even ignores its argument, since + * it does not happen very often, and one has to walk up the tree since + * this might be a newly instantiated cursor for an intermediate window + * between the one the pointer is in and the one that the last cursor was + * instantiated from. + */ +void +WindowHasNewCursor(WindowPtr pWin) +{ + PostNewCursor(); +} + +_X_EXPORT void +NewCurrentScreen(ScreenPtr newScreen, int x, int y) +{ + sprite.hotPhys.x = x; + sprite.hotPhys.y = y; + if (newScreen != sprite.hotPhys.pScreen) + ConfineCursorToWindow(WindowTable[newScreen->myNum], TRUE, FALSE); +} + + +int +ProcWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + + int x, y; + + ScreenPtr newScreen; + + REQUEST(xWarpPointerReq); + + REQUEST_SIZE_MATCH(xWarpPointerReq); + + + if (stuff->dstWid != None) { + dest = SecurityLookupWindow(stuff->dstWid, client, SecurityReadAccess); + if (!dest) + return BadWindow; + } + x = sprite.hotPhys.x; + y = sprite.hotPhys.y; + + if (stuff->srcWid != None) { + int winX, winY; + + XID winID = stuff->srcWid; + + WindowPtr source; + + source = SecurityLookupWindow(winID, client, SecurityReadAccess); + if (!source) + return BadWindow; + + winX = source->drawable.x; + winY = source->drawable.y; + if (source->drawable.pScreen != sprite.hotPhys.pScreen || + x < winX + stuff->srcX || + y < winY + stuff->srcY || + (stuff->srcWidth != 0 && + winX + stuff->srcX + (int) stuff->srcWidth < x) || + (stuff->srcHeight != 0 && + winY + stuff->srcY + (int) stuff->srcHeight < y) || + !PointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) { + x = dest->drawable.x; + y = dest->drawable.y; + newScreen = dest->drawable.pScreen; + } + else + newScreen = sprite.hotPhys.pScreen; + + x += stuff->dstX; + y += stuff->dstY; + + if (x < 0) + x = 0; + else if (x >= newScreen->width) + x = newScreen->width - 1; + if (y < 0) + y = 0; + else if (y >= newScreen->height) + y = newScreen->height - 1; + + if (newScreen == sprite.hotPhys.pScreen) { + if (x < sprite.physLimits.x1) + x = sprite.physLimits.x1; + else if (x >= sprite.physLimits.x2) + x = sprite.physLimits.x2 - 1; + if (y < sprite.physLimits.y1) + y = sprite.physLimits.y1; + else if (y >= sprite.physLimits.y2) + y = sprite.physLimits.y2 - 1; + if (sprite.hotShape) + ConfineToShape(sprite.hotShape, &x, &y); + (*newScreen->SetCursorPosition) (newScreen, x, y, TRUE); + } + else if (!PointerConfinedToScreen()) { + NewCurrentScreen(newScreen, x, y); + } + return Success; +} + +static Bool +BorderSizeNotEmpty(WindowPtr pWin) +{ + if (REGION_NOTEMPTY(&pWin->borderSize)) + return TRUE; + + return FALSE; +} + +/* "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a + passive grab set on the window to be activated. */ + +static Bool +CheckPassiveGrabsOnWindow(WindowPtr pWin, + register DeviceIntPtr device, + register xEvent *xE, int count) +{ + GrabPtr grab = wPassiveGrabs(pWin); + + GrabRec tempGrab; + + xEvent *dxE; + + if (!grab) + return FALSE; + tempGrab.window = pWin; + tempGrab.device = device; + tempGrab.type = xE->u.u.type; + tempGrab.detail.exact = xE->u.u.detail; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + for (; grab; grab = grab->next) { + tempGrab.modifierDevice = grab->modifierDevice; + if ((device == grab->modifierDevice) && ((xE->u.u.type == KeyPress) + )) + tempGrab.modifiersDetail.exact = + grab->modifierDevice->key->prev_state; + else + tempGrab.modifiersDetail.exact = + grab->modifierDevice->key->state; + if (GrabMatchesSecond(&tempGrab, grab) && + (!grab->confineTo || + (grab->confineTo->realized && + BorderSizeNotEmpty(grab->confineTo)))) { + (*device->ActivateGrab) (device, grab, currentTime, TRUE); + + FixUpEventFromWindow(xE, grab->window, None, TRUE); + + (void) TryClientEvents(rClient(grab), xE, count, + filters[xE->u.u.type], + filters[xE->u.u.type], grab); + + if (device->sync.state == FROZEN_NO_EVENT) { + if (device->sync.evcount < count) { + Must_have_memory = TRUE; /* XXX */ + device->sync.event = (xEvent *) realloc(device->sync.event, + count * + sizeof(xEvent)); + Must_have_memory = FALSE; /* XXX */ + } + device->sync.evcount = count; + for (dxE = device->sync.event; --count >= 0; dxE++, xE++) + *dxE = *xE; + device->sync.state = FROZEN_WITH_EVENT; + } + return TRUE; + } + } + return FALSE; +} + +/** +"CheckDeviceGrabs" handles both keyboard and pointer events that may cause +a passive grab to be activated. If the event is a keyboard event, the +ancestors of the focus window are traced down and tried to see if they have +any passive grabs to be activated. If the focus window itself is reached and +it's descendants contain they pointer, the ancestors of the window that the +pointer is in are then traced down starting at the focus window, otherwise no +grabs are activated. If the event is a pointer event, the ancestors of the +window that the pointer is in are traced down starting at the root until +CheckPassiveGrabs causes a passive grab to activate or all the windows are +tried. PRH +*/ + +Bool +CheckDeviceGrabs(register DeviceIntPtr device, register xEvent *xE, + int checkFirst, int count) +{ + int i; + + WindowPtr pWin = NULL; + + FocusClassPtr focus = device->focus; + + if (((xE->u.u.type == ButtonPress) + ) && (device->button->buttonsDown != 1)) + return FALSE; + + i = checkFirst; + + if (focus) { + for (; i < focus->traceGood; i++) { + pWin = focus->trace[i]; + if (pWin->optional && + CheckPassiveGrabsOnWindow(pWin, device, xE, count)) + return TRUE; + } + + if ((focus->win == NoneWin) || + (i >= spriteTraceGood) || + ((i > checkFirst) && (pWin != spriteTrace[i - 1]))) + return FALSE; + } + + for (; i < spriteTraceGood; i++) { + pWin = spriteTrace[i]; + if (pWin->optional && + CheckPassiveGrabsOnWindow(pWin, device, xE, count)) + return TRUE; + } + + return FALSE; +} + +void +DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count) +{ + WindowPtr focus = keybd->focus->win; + + int mskidx = 0; + + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + if (!focus) + return; + if (focus == PointerRootWin) { + DeliverDeviceEvents(window, xE, NullGrab, NullWindow, keybd, count); + return; + } + if ((focus == window) || IsParent(focus, window)) { + if (DeliverDeviceEvents(window, xE, NullGrab, focus, keybd, count)) + return; + } + /* just deliver it to the focus window */ + FixUpEventFromWindow(xE, focus, None, FALSE); + if (xE->u.u.type & EXTENSION_EVENT_BASE) + mskidx = keybd->id; + (void) DeliverEventsToWindow(focus, xE, count, filters[xE->u.u.type], + NullGrab, mskidx); +} + +void +DeliverGrabbedEvent(register xEvent *xE, register DeviceIntPtr thisDev, + Bool deactivateGrab, int count) +{ + GrabPtr grab = thisDev->grab; + + int deliveries = 0; + + DeviceIntPtr dev; + + xEvent *dxE; + + if (grab->ownerEvents) { + WindowPtr focus; + + if (thisDev->focus) { + focus = thisDev->focus->win; + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + } + else + focus = PointerRootWin; + if (focus == PointerRootWin) + deliveries = DeliverDeviceEvents(sprite.win, xE, grab, NullWindow, + thisDev, count); + else if (focus && (focus == sprite.win || IsParent(focus, sprite.win))) + deliveries = DeliverDeviceEvents(sprite.win, xE, grab, focus, + thisDev, count); + else if (focus) + deliveries = DeliverDeviceEvents(focus, xE, grab, focus, + thisDev, count); + } + if (!deliveries) { + FixUpEventFromWindow(xE, grab->window, None, TRUE); + deliveries = TryClientEvents(rClient(grab), xE, count, + (Mask) grab->eventMask, + filters[xE->u.u.type], grab); + if (deliveries && (xE->u.u.type == MotionNotify + )) + thisDev->valuator->motionHintWindow = grab->window; + } + if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify + )) + switch (thisDev->sync.state) { + case FREEZE_BOTH_NEXT_EVENT: + for (dev = inputInfo.devices; dev; dev = dev->next) { + if (dev == thisDev) + continue; + FreezeThaw(dev, TRUE); + if ((dev->sync.state == FREEZE_BOTH_NEXT_EVENT) && + (CLIENT_BITS(dev->grab->resource) == + CLIENT_BITS(thisDev->grab->resource))) + dev->sync.state = FROZEN_NO_EVENT; + else + dev->sync.other = thisDev->grab; + } + /* fall through */ + case FREEZE_NEXT_EVENT: + thisDev->sync.state = FROZEN_WITH_EVENT; + FreezeThaw(thisDev, TRUE); + if (thisDev->sync.evcount < count) { + Must_have_memory = TRUE; /* XXX */ + thisDev->sync.event = (xEvent *) realloc(thisDev->sync.event, + count * + sizeof(xEvent)); + Must_have_memory = FALSE; /* XXX */ + } + thisDev->sync.evcount = count; + for (dxE = thisDev->sync.event; --count >= 0; dxE++, xE++) + *dxE = *xE; + break; + } +} + +void +ProcessKeyboardEvent(register xEvent *xE, register DeviceIntPtr keybd, + int count) +{ + int key, bit; + + BYTE *kptr; + + int i; + + CARD8 modifiers; + + CARD16 mask; + + GrabPtr grab = keybd->grab; + + Bool deactivateGrab = FALSE; + + KeyClassPtr keyc = keybd->key; + + + if (!syncEvents.playingEvents) { + NoticeTime(xE); + if (DeviceEventCallback) { + DeviceEventInfoRec eventinfo; + + eventinfo.events = xE; + eventinfo.count = count; + CallCallbacks(&DeviceEventCallback, (pointer) &eventinfo); + } + } + XE_KBPTR.state = (keyc->state | inputInfo.pointer->button->state); + XE_KBPTR.rootX = sprite.hot.x; + XE_KBPTR.rootY = sprite.hot.y; + key = xE->u.u.detail; + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + modifiers = keyc->modifierMap[key]; + +#ifdef DEBUG + if ((xkbDebugFlags & 0x4) && + ((xE->u.u.type == KeyPress) || (xE->u.u.type == KeyRelease))) { + ErrorF("CoreProcessKbdEvent: Key %d %s\n", key, + (xE->u.u.type == KeyPress ? "down" : "up")); + } +#endif + switch (xE->u.u.type) { + case KeyPress: + if (*kptr & bit) { /* allow ddx to generate multiple downs */ + if (!modifiers) { + xE->u.u.type = KeyRelease; + (*keybd->public.processInputProc) (xE, keybd, count); + xE->u.u.type = KeyPress; + /* release can have side effects, don't fall through */ + (*keybd->public.processInputProc) (xE, keybd, count); + } + return; + } + inputInfo.pointer->valuator->motionHintWindow = NullWindow; + + *kptr |= bit; + keyc->prev_state = keyc->state; + for (i = 0, mask = 1; modifiers; i++, mask <<= 1) { + if (mask & modifiers) { + /* This key affects modifier "i" */ + keyc->modifierKeyCount[i]++; + keyc->state |= mask; + modifiers &= ~mask; + } + } + if (!grab && CheckDeviceGrabs(keybd, xE, 0, count)) { + keybd->activatingKey = key; + return; + } + break; + case KeyRelease: + if (!(*kptr & bit)) /* guard against duplicates */ + return; + inputInfo.pointer->valuator->motionHintWindow = NullWindow; + + *kptr &= ~bit; + keyc->prev_state = keyc->state; + for (i = 0, mask = 1; modifiers; i++, mask <<= 1) { + if (mask & modifiers) { + /* This key affects modifier "i" */ + if (--keyc->modifierKeyCount[i] <= 0) { + keyc->state &= ~mask; + keyc->modifierKeyCount[i] = 0; + } + modifiers &= ~mask; + } + } + if (keybd->fromPassiveGrab && (key == keybd->activatingKey)) + deactivateGrab = TRUE; + break; + default: + FatalError("Impossible keyboard event"); + } + if (grab) + DeliverGrabbedEvent(xE, keybd, deactivateGrab, count); + else + DeliverFocusedEvent(keybd, xE, sprite.win, count); + if (deactivateGrab) + (*keybd->DeactivateGrab) (keybd); + +} + + +void +ProcessPointerEvent(register xEvent *xE, register DeviceIntPtr mouse, int count) +{ + GrabPtr grab = mouse->grab; + + Bool deactivateGrab = FALSE; + + ButtonClassPtr butc = mouse->button; + + + if (!syncEvents.playingEvents) + NoticeTime(xE) + XE_KBPTR.state = (butc->state | ( + inputInfo.keyboard->key->state + )); + { + NoticeTime(xE); + if (DeviceEventCallback) { + DeviceEventInfoRec eventinfo; + + /* see comment in EnqueueEvents regarding the next three lines */ + if (xE->u.u.type == MotionNotify) + XE_KBPTR.root = + WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id; + eventinfo.events = xE; + eventinfo.count = count; + CallCallbacks(&DeviceEventCallback, (pointer) &eventinfo); + } + } + if (xE->u.u.type != MotionNotify) { + int key; + + BYTE *kptr; + + int bit; + + XE_KBPTR.rootX = sprite.hot.x; + XE_KBPTR.rootY = sprite.hot.y; + + key = xE->u.u.detail; + kptr = &butc->down[key >> 3]; + bit = 1 << (key & 7); + switch (xE->u.u.type) { + case ButtonPress: + mouse->valuator->motionHintWindow = NullWindow; + if (!(*kptr & bit)) + butc->buttonsDown++; + butc->motionMask = ButtonMotionMask; + *kptr |= bit; + if (xE->u.u.detail == 0) + return; + if (xE->u.u.detail <= 5) + butc->state |= (Button1Mask >> 1) << xE->u.u.detail; + filters[MotionNotify] = Motion_Filter(butc); + if (!grab) + if (CheckDeviceGrabs(mouse, xE, 0, count)) + return; + break; + case ButtonRelease: + mouse->valuator->motionHintWindow = NullWindow; + if (*kptr & bit) + --butc->buttonsDown; + if (!butc->buttonsDown) + butc->motionMask = 0; + *kptr &= ~bit; + if (xE->u.u.detail == 0) + return; + if (xE->u.u.detail <= 5) + butc->state &= ~((Button1Mask >> 1) << xE->u.u.detail); + filters[MotionNotify] = Motion_Filter(butc); + if (!butc->state && mouse->fromPassiveGrab) + deactivateGrab = TRUE; + break; + default: + FatalError("bogus pointer event from ddx"); + } + } + else if (!CheckMotion(xE)) + return; + if (grab) + DeliverGrabbedEvent(xE, mouse, deactivateGrab, count); + else + DeliverDeviceEvents(sprite.win, xE, NullGrab, NullWindow, mouse, count); + if (deactivateGrab) + (*mouse->DeactivateGrab) (mouse); +} + +#define AtMostOneClient \ + (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) + +void +RecalculateDeliverableEvents(pWin) +WindowPtr pWin; +{ + OtherClients *others; + + WindowPtr pChild; + + pChild = pWin; + while (1) { + if (pChild->optional) { + pChild->optional->otherEventMasks = 0; + for (others = wOtherClients(pChild); others; others = others->next) { + pChild->optional->otherEventMasks |= others->mask; + } + } + pChild->deliverableEvents = pChild->eventMask | + wOtherEventMasks(pChild); + if (pChild->parent) + pChild->deliverableEvents |= + (pChild->parent->deliverableEvents & + ~wDontPropagateMask(pChild) & PropagateMask); + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +/** + * + * \param value must conform to DeleteType + */ +int +OtherClientGone(pointer value, XID id) +{ + OtherClientsPtr other, prev; + + WindowPtr pWin = (WindowPtr) value; + + prev = 0; + for (other = wOtherClients(pWin); other; other = other->next) { + if (other->resource == id) { + if (prev) + prev->next = other->next; + else { + if (!(pWin->optional->otherClients = other->next)) + CheckWindowOptionalNeed(pWin); + } + free(other); + RecalculateDeliverableEvents(pWin); + return (Success); + } + prev = other; + } + FatalError("client not on event list"); + /*NOTREACHED*/ return -1; /* make compiler happy */ +} + +int +EventSelectForWindow(register WindowPtr pWin, register ClientPtr client, + Mask mask) +{ + Mask check; + + OtherClients *others; + + if (mask & ~AllEventMasks) { + client->errorValue = mask; + return BadValue; + } + check = (mask & AtMostOneClient); + if (check & (pWin->eventMask | wOtherEventMasks(pWin))) { /* It is illegal for two different + clients to select on any of the + events for AtMostOneClient. However, + it is OK, for some client to + continue selecting on one of those + events. */ + if ((wClient(pWin) != client) && (check & pWin->eventMask)) + return BadAccess; + for (others = wOtherClients(pWin); others; others = others->next) { + if (!SameClient(others, client) && (check & others->mask)) + return BadAccess; + } + } + if (wClient(pWin) == client) { + check = pWin->eventMask; + pWin->eventMask = mask; + } + else { + for (others = wOtherClients(pWin); others; others = others->next) { + if (SameClient(others, client)) { + check = others->mask; + if (mask == 0) { + FreeResource(others->resource, RT_NONE); + return Success; + } + else + others->mask = mask; + goto maskSet; + } + } + check = 0; + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + others = malloc(sizeof(OtherClients)); + if (!others) + return BadAlloc; + others->mask = mask; + others->resource = FakeClientID(client->index); + others->next = pWin->optional->otherClients; + pWin->optional->otherClients = others; + if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer) pWin)) + return BadAlloc; + } + maskSet: + if ((inputInfo.pointer->valuator->motionHintWindow == pWin) && + (mask & PointerMotionHintMask) && + !(check & PointerMotionHintMask) && !inputInfo.pointer->grab) + inputInfo.pointer->valuator->motionHintWindow = NullWindow; + + RecalculateDeliverableEvents(pWin); + return Success; +} + +int +EventSuppressForWindow(register WindowPtr pWin, register ClientPtr client, + Mask mask, Bool *checkOptional) +{ + int i, free; + + if (mask & ~PropagateMask) { + client->errorValue = mask; + return BadValue; + } + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + if (!mask) + i = 0; + else { + for (i = DNPMCOUNT, free = 0; --i > 0;) { + if (!DontPropagateRefCnts[i]) + free = i; + else if (mask == DontPropagateMasks[i]) + break; + } + if (!i && free) { + i = free; + DontPropagateMasks[i] = mask; + } + } + if (i || !mask) { + pWin->dontPropagate = i; + if (i) + DontPropagateRefCnts[i]++; + if (pWin->optional) { + pWin->optional->dontPropagateMask = mask; + *checkOptional = TRUE; + } + } + else { + if (!pWin->optional && !MakeWindowOptional(pWin)) { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]++; + return BadAlloc; + } + pWin->dontPropagate = 0; + pWin->optional->dontPropagateMask = mask; + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +static WindowPtr +CommonAncestor(register WindowPtr a, register WindowPtr b) +{ + for (b = b->parent; b; b = b->parent) + if (IsParent(b, a)) + return b; + return NullWindow; +} + +static void +EnterLeaveEvent(int type, + int mode, int detail, register WindowPtr pWin, Window child) +{ + xEvent event; + + DeviceIntPtr keybd = inputInfo.keyboard; + + WindowPtr focus; + + DeviceIntPtr mouse = inputInfo.pointer; + + GrabPtr grab = mouse->grab; + + Mask mask; + + if ((pWin == mouse->valuator->motionHintWindow) && + (detail != NotifyInferior)) + mouse->valuator->motionHintWindow = NullWindow; + if (grab) { + mask = (pWin == grab->window) ? grab->eventMask : 0; + if (grab->ownerEvents) + mask |= EventMaskForClient(pWin, rClient(grab)); + } + else { + mask = pWin->eventMask | wOtherEventMasks(pWin); + } + if (mask & filters[type]) { + event.u.u.type = type; + event.u.u.detail = detail; + event.u.enterLeave.time = currentTime.milliseconds; + event.u.enterLeave.rootX = sprite.hot.x; + event.u.enterLeave.rootY = sprite.hot.y; + /* Counts on the same initial structure of crossing & button events! */ + FixUpEventFromWindow(&event, pWin, None, FALSE); + /* Enter/Leave events always set child */ + event.u.enterLeave.child = child; + event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? + ELFlagSameScreen : 0; + event.u.enterLeave.state = keybd->key->state | mouse->button->state; + event.u.enterLeave.mode = mode; + focus = keybd->focus->win; + if ((focus != NoneWin) && + ((pWin == focus) || (focus == PointerRootWin) || + IsParent(focus, pWin))) + event.u.enterLeave.flags |= ELFlagFocus; + if (grab) + (void) TryClientEvents(rClient(grab), &event, 1, mask, + filters[type], grab); + else + (void) DeliverEventsToWindow(pWin, &event, 1, filters[type], + NullGrab, 0); + } + if ((type == EnterNotify) && (mask & KeymapStateMask)) { + xKeymapEvent ke; + + memmove((char *) &ke.map[0], (char *) &keybd->key->down[1], 31); + ke.type = KeymapNotify; + if (grab) + (void) TryClientEvents(rClient(grab), (xEvent *) &ke, 1, mask, + KeymapStateMask, grab); + else + (void) DeliverEventsToWindow(pWin, (xEvent *) &ke, 1, + KeymapStateMask, NullGrab, 0); + } +} + +static void +EnterNotifies(WindowPtr ancestor, WindowPtr child, int mode, int detail) +{ + WindowPtr parent = child->parent; + + if (ancestor == parent) + return; + EnterNotifies(ancestor, parent, mode, detail); + EnterLeaveEvent(EnterNotify, mode, detail, parent, child->drawable.id); +} + +static void +LeaveNotifies(WindowPtr child, WindowPtr ancestor, int mode, int detail) +{ + WindowPtr pWin; + + if (ancestor == child) + return; + for (pWin = child->parent; pWin != ancestor; pWin = pWin->parent) { + EnterLeaveEvent(LeaveNotify, mode, detail, pWin, child->drawable.id); + child = pWin; + } +} + +static void +DoEnterLeaveEvents(WindowPtr fromWin, WindowPtr toWin, int mode) +{ + if (fromWin == toWin) + return; + if (IsParent(fromWin, toWin)) { + EnterLeaveEvent(LeaveNotify, mode, NotifyInferior, fromWin, None); + EnterNotifies(fromWin, toWin, mode, NotifyVirtual); + EnterLeaveEvent(EnterNotify, mode, NotifyAncestor, toWin, None); + } + else if (IsParent(toWin, fromWin)) { + EnterLeaveEvent(LeaveNotify, mode, NotifyAncestor, fromWin, None); + LeaveNotifies(fromWin, toWin, mode, NotifyVirtual); + EnterLeaveEvent(EnterNotify, mode, NotifyInferior, toWin, None); + } + else { /* neither fromWin nor toWin is descendent of the other */ + WindowPtr common = CommonAncestor(toWin, fromWin); + + /* common == NullWindow ==> different screens */ + EnterLeaveEvent(LeaveNotify, mode, NotifyNonlinear, fromWin, None); + LeaveNotifies(fromWin, common, mode, NotifyNonlinearVirtual); + EnterNotifies(common, toWin, mode, NotifyNonlinearVirtual); + EnterLeaveEvent(EnterNotify, mode, NotifyNonlinear, toWin, None); + } +} + +static void +FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, + register WindowPtr pWin) +{ + xEvent event; + + event.u.focus.mode = mode; + event.u.u.type = type; + event.u.u.detail = detail; + event.u.focus.window = pWin->drawable.id; + (void) DeliverEventsToWindow(pWin, &event, 1, filters[type], NullGrab, 0); + if ((type == FocusIn) && + ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) { + xKeymapEvent ke; + + memmove((char *) &ke.map[0], (char *) &dev->key->down[1], 31); + ke.type = KeymapNotify; + (void) DeliverEventsToWindow(pWin, (xEvent *) &ke, 1, + KeymapStateMask, NullGrab, 0); + } +} + + /* + * recursive because it is easier + * no-op if child not descended from ancestor + */ +static Bool +FocusInEvents(DeviceIntPtr dev, + WindowPtr ancestor, WindowPtr child, WindowPtr skipChild, + int mode, int detail, Bool doAncestor) +{ + if (child == NullWindow) + return ancestor == NullWindow; + if (ancestor == child) { + if (doAncestor) + FocusEvent(dev, FocusIn, mode, detail, child); + return TRUE; + } + if (FocusInEvents(dev, ancestor, child->parent, skipChild, mode, detail, + doAncestor)) { + if (child != skipChild) + FocusEvent(dev, FocusIn, mode, detail, child); + return TRUE; + } + return FALSE; +} + +/* dies horribly if ancestor is not an ancestor of child */ +static void +FocusOutEvents(DeviceIntPtr dev, + WindowPtr child, WindowPtr ancestor, + int mode, int detail, Bool doAncestor) +{ + WindowPtr pWin; + + for (pWin = child; pWin != ancestor; pWin = pWin->parent) + FocusEvent(dev, FocusOut, mode, detail, pWin); + if (doAncestor) + FocusEvent(dev, FocusOut, mode, detail, ancestor); +} + +void +DoFocusEvents(DeviceIntPtr dev, WindowPtr fromWin, WindowPtr toWin, int mode) +{ + int out, in; /* for holding details for to/from + PointerRoot/None */ + int i; + + if (fromWin == toWin) + return; + out = (fromWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; + in = (toWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot; + /* wrong values if neither, but then not referenced */ + + if ((toWin == NullWindow) || (toWin == PointerRootWin)) { + if ((fromWin == NullWindow) || (fromWin == PointerRootWin)) { + if (fromWin == PointerRootWin) + FocusOutEvents(dev, sprite.win, ROOT, mode, NotifyPointer, + TRUE); + /* Notify all the roots */ + for (i = 0; i < screenInfo.numScreens; i++) + FocusEvent(dev, FocusOut, mode, out, WindowTable[i]); + } + else { + if (IsParent(fromWin, sprite.win)) + FocusOutEvents(dev, sprite.win, fromWin, mode, NotifyPointer, + FALSE); + FocusEvent(dev, FocusOut, mode, NotifyNonlinear, fromWin); + /* next call catches the root too, if the screen changed */ + FocusOutEvents(dev, fromWin->parent, NullWindow, mode, + NotifyNonlinearVirtual, FALSE); + } + /* Notify all the roots */ + for (i = 0; i < screenInfo.numScreens; i++) + FocusEvent(dev, FocusIn, mode, in, WindowTable[i]); + if (toWin == PointerRootWin) + (void) FocusInEvents(dev, ROOT, sprite.win, NullWindow, mode, + NotifyPointer, TRUE); + } + else { + if ((fromWin == NullWindow) || (fromWin == PointerRootWin)) { + if (fromWin == PointerRootWin) + FocusOutEvents(dev, sprite.win, ROOT, mode, NotifyPointer, + TRUE); + for (i = 0; i < screenInfo.numScreens; i++) + FocusEvent(dev, FocusOut, mode, out, WindowTable[i]); + if (toWin->parent != NullWindow) + (void) FocusInEvents(dev, ROOT, toWin, toWin, mode, + NotifyNonlinearVirtual, TRUE); + FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin); + if (IsParent(toWin, sprite.win)) + (void) FocusInEvents(dev, toWin, sprite.win, NullWindow, mode, + NotifyPointer, FALSE); + } + else { + if (IsParent(toWin, fromWin)) { + FocusEvent(dev, FocusOut, mode, NotifyAncestor, fromWin); + FocusOutEvents(dev, fromWin->parent, toWin, mode, + NotifyVirtual, FALSE); + FocusEvent(dev, FocusIn, mode, NotifyInferior, toWin); + if ((IsParent(toWin, sprite.win)) && + (sprite.win != fromWin) && + (!IsParent(fromWin, sprite.win)) && + (!IsParent(sprite.win, fromWin))) + (void) FocusInEvents(dev, toWin, sprite.win, NullWindow, + mode, NotifyPointer, FALSE); + } + else if (IsParent(fromWin, toWin)) { + if ((IsParent(fromWin, sprite.win)) && + (sprite.win != fromWin) && + (!IsParent(toWin, sprite.win)) && + (!IsParent(sprite.win, toWin))) + FocusOutEvents(dev, sprite.win, fromWin, mode, + NotifyPointer, FALSE); + FocusEvent(dev, FocusOut, mode, NotifyInferior, fromWin); + (void) FocusInEvents(dev, fromWin, toWin, toWin, mode, + NotifyVirtual, FALSE); + FocusEvent(dev, FocusIn, mode, NotifyAncestor, toWin); + } + else { + /* neither fromWin or toWin is child of other */ + WindowPtr common = CommonAncestor(toWin, fromWin); + + /* common == NullWindow ==> different screens */ + if (IsParent(fromWin, sprite.win)) + FocusOutEvents(dev, sprite.win, fromWin, mode, + NotifyPointer, FALSE); + FocusEvent(dev, FocusOut, mode, NotifyNonlinear, fromWin); + if (fromWin->parent != NullWindow) + FocusOutEvents(dev, fromWin->parent, common, mode, + NotifyNonlinearVirtual, FALSE); + if (toWin->parent != NullWindow) + (void) FocusInEvents(dev, common, toWin, toWin, mode, + NotifyNonlinearVirtual, FALSE); + FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin); + if (IsParent(toWin, sprite.win)) + (void) FocusInEvents(dev, toWin, sprite.win, NullWindow, + mode, NotifyPointer, FALSE); + } + } + } +} + +int +SetInputFocus(ClientPtr client, + DeviceIntPtr dev, + Window focusID, CARD8 revertTo, Time ctime, Bool followOK) +{ + FocusClassPtr focus; + + WindowPtr focusWin; + + int mode; + + TimeStamp time; + + UpdateCurrentTime(); + if ((revertTo != RevertToParent) && + (revertTo != RevertToPointerRoot) && + (revertTo != RevertToNone) && + ((revertTo != RevertToFollowKeyboard) || !followOK)) { + client->errorValue = revertTo; + return BadValue; + } + time = ClientTimeToServerTime(ctime); + if ((focusID == None) || (focusID == PointerRoot)) + focusWin = (WindowPtr) (long) focusID; + else if ((focusID == FollowKeyboard) && followOK) + focusWin = inputInfo.keyboard->focus->win; + else if (!(focusWin = SecurityLookupWindow(focusID, client, + SecurityReadAccess))) + return BadWindow; + else { + /* It is a match error to try to set the input focus to an + unviewable window. */ + + if (!focusWin->realized) + return (BadMatch); + } + focus = dev->focus; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, focus->time) == EARLIER)) + return Success; + mode = (dev->grab) ? NotifyWhileGrabbed : NotifyNormal; + if (focus->win == FollowKeyboardWin) + DoFocusEvents(dev, inputInfo.keyboard->focus->win, focusWin, mode); + else + DoFocusEvents(dev, focus->win, focusWin, mode); + focus->time = time; + focus->revert = revertTo; + if (focusID == FollowKeyboard) + focus->win = FollowKeyboardWin; + else + focus->win = focusWin; + if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) + focus->traceGood = 0; + else { + int depth = 0; + + WindowPtr pWin; + + for (pWin = focusWin; pWin; pWin = pWin->parent) + depth++; + if (depth > focus->traceSize) { + focus->traceSize = depth + 1; + Must_have_memory = TRUE; /* XXX */ + focus->trace = (WindowPtr *) realloc(focus->trace, + focus->traceSize * + sizeof(WindowPtr)); + Must_have_memory = FALSE; /* XXX */ + } + focus->traceGood = depth; + for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) + focus->trace[depth] = pWin; + } + return Success; +} + +int +ProcSetInputFocus(client) +ClientPtr client; +{ + REQUEST(xSetInputFocusReq); + + REQUEST_SIZE_MATCH(xSetInputFocusReq); + return SetInputFocus(client, inputInfo.keyboard, stuff->focus, + stuff->revertTo, stuff->time, FALSE); +} + +int +ProcGetInputFocus(ClientPtr client) +{ + xGetInputFocusReply rep = {0}; + + /* REQUEST(xReq); */ + FocusClassPtr focus = inputInfo.keyboard->focus; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (focus->win == NoneWin) + rep.focus = None; + else if (focus->win == PointerRootWin) + rep.focus = PointerRoot; + else + rep.focus = focus->win->drawable.id; + rep.revertTo = focus->revert; + WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); + return Success; +} + +int +ProcGrabPointer(ClientPtr client) +{ + xGrabPointerReply rep; + + DeviceIntPtr device = inputInfo.pointer; + + GrabPtr grab; + + WindowPtr pWin, confineTo; + + CursorPtr cursor, oldCursor; + + REQUEST(xGrabPointerReq); + TimeStamp time; + + REQUEST_SIZE_MATCH(xGrabPointerReq); + UpdateCurrentTime(); + if ((stuff->pointerMode != GrabModeSync) && + (stuff->pointerMode != GrabModeAsync)) { + client->errorValue = stuff->pointerMode; + return BadValue; + } + if ((stuff->keyboardMode != GrabModeSync) && + (stuff->keyboardMode != GrabModeAsync)) { + client->errorValue = stuff->keyboardMode; + return BadValue; + } + if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) { + client->errorValue = stuff->ownerEvents; + return BadValue; + } + if (stuff->eventMask & ~PointerGrabMask) { + client->errorValue = stuff->eventMask; + return BadValue; + } + pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + if (stuff->confineTo == None) + confineTo = NullWindow; + else { + confineTo = SecurityLookupWindow(stuff->confineTo, client, + SecurityReadAccess); + if (!confineTo) + return BadWindow; + } + if (stuff->cursor == None) + cursor = NullCursor; + else { + cursor = (CursorPtr) SecurityLookupIDByType(client, stuff->cursor, + RT_CURSOR, + SecurityReadAccess); + if (!cursor) { + client->errorValue = stuff->cursor; + return BadCursor; + } + } + /* at this point, some sort of reply is guaranteed. */ + time = ClientTimeToServerTime(stuff->time); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + grab = device->grab; + if ((grab) && !SameClient(grab, client)) + rep.status = AlreadyGrabbed; + else if ((!pWin->realized) || + (confineTo && + !(confineTo->realized && BorderSizeNotEmpty(confineTo)))) + rep.status = GrabNotViewable; + else if (device->sync.frozen && + device->sync.other && !SameClient(device->sync.other, client)) + rep.status = GrabFrozen; + else if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, device->grabTime) == EARLIER)) + rep.status = GrabInvalidTime; + else { + GrabRec tempGrab; + + oldCursor = NullCursor; + if (grab) { + if (grab->confineTo && !confineTo) + ConfineCursorToWindow(ROOT, FALSE, FALSE); + oldCursor = grab->cursor; + } + tempGrab.cursor = cursor; + tempGrab.resource = client->clientAsMask; + tempGrab.ownerEvents = stuff->ownerEvents; + tempGrab.eventMask = stuff->eventMask; + tempGrab.confineTo = confineTo; + tempGrab.window = pWin; + tempGrab.keyboardMode = stuff->keyboardMode; + tempGrab.pointerMode = stuff->pointerMode; + tempGrab.device = device; + (*device->ActivateGrab) (device, &tempGrab, time, FALSE); + if (oldCursor) + FreeCursor(oldCursor, (Cursor) 0); + rep.status = GrabSuccess; + } + WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); + return Success; +} + +int +ProcChangeActivePointerGrab(ClientPtr client) +{ + DeviceIntPtr device = inputInfo.pointer; + + GrabPtr grab = device->grab; + + CursorPtr newCursor, oldCursor; + + REQUEST(xChangeActivePointerGrabReq); + TimeStamp time; + + REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); + if (stuff->eventMask & ~PointerGrabMask) { + client->errorValue = stuff->eventMask; + return BadValue; + } + if (stuff->cursor == None) + newCursor = NullCursor; + else { + newCursor = (CursorPtr) SecurityLookupIDByType(client, stuff->cursor, + RT_CURSOR, + SecurityReadAccess); + if (!newCursor) { + client->errorValue = stuff->cursor; + return BadCursor; + } + } + if (!grab) + return Success; + if (!SameClient(grab, client)) + return Success; + time = ClientTimeToServerTime(stuff->time); + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, device->grabTime) == EARLIER)) + return Success; + oldCursor = grab->cursor; + grab->cursor = newCursor; + if (newCursor) + newCursor->refcnt++; + PostNewCursor(); + if (oldCursor) + FreeCursor(oldCursor, (Cursor) 0); + grab->eventMask = stuff->eventMask; + return Success; +} + +int +ProcUngrabPointer(ClientPtr client) +{ + DeviceIntPtr device = inputInfo.pointer; + + GrabPtr grab; + + TimeStamp time; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + grab = device->grab; + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->grabTime) != EARLIER) && + (grab) && SameClient(grab, client)) + (*device->DeactivateGrab) (device); + return Success; +} + +int +GrabDevice(register ClientPtr client, register DeviceIntPtr dev, + unsigned this_mode, unsigned other_mode, Window grabWindow, + unsigned ownerEvents, Time ctime, Mask mask, CARD8 *status) +{ + WindowPtr pWin; + + GrabPtr grab; + + TimeStamp time; + + UpdateCurrentTime(); + if ((this_mode != GrabModeSync) && (this_mode != GrabModeAsync)) { + client->errorValue = this_mode; + return BadValue; + } + if ((other_mode != GrabModeSync) && (other_mode != GrabModeAsync)) { + client->errorValue = other_mode; + return BadValue; + } + if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) { + client->errorValue = ownerEvents; + return BadValue; + } + pWin = SecurityLookupWindow(grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + time = ClientTimeToServerTime(ctime); + grab = dev->grab; + if (grab && !SameClient(grab, client)) + *status = AlreadyGrabbed; + else if (!pWin->realized) + *status = GrabNotViewable; + else if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, dev->grabTime) == EARLIER)) + *status = GrabInvalidTime; + else if (dev->sync.frozen && + dev->sync.other && !SameClient(dev->sync.other, client)) + *status = GrabFrozen; + else { + GrabRec tempGrab; + + tempGrab.window = pWin; + tempGrab.resource = client->clientAsMask; + tempGrab.ownerEvents = ownerEvents; + tempGrab.keyboardMode = this_mode; + tempGrab.pointerMode = other_mode; + tempGrab.eventMask = mask; + tempGrab.device = dev; + (*dev->ActivateGrab) (dev, &tempGrab, time, FALSE); + *status = GrabSuccess; + } + return Success; +} + +int +ProcGrabKeyboard(ClientPtr client) +{ + xGrabKeyboardReply rep; + + REQUEST(xGrabKeyboardReq); + int result; + + REQUEST_SIZE_MATCH(xGrabKeyboardReq); + result = GrabDevice(client, inputInfo.keyboard, stuff->keyboardMode, + stuff->pointerMode, stuff->grabWindow, + stuff->ownerEvents, stuff->time, + KeyPressMask | KeyReleaseMask, &rep.status); + if (result != Success) + return result; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); + return Success; +} + +int +ProcUngrabKeyboard(ClientPtr client) +{ + DeviceIntPtr device = inputInfo.keyboard; + + GrabPtr grab; + + TimeStamp time; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + grab = device->grab; + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->grabTime) != EARLIER) && + (grab) && SameClient(grab, client)) + (*device->DeactivateGrab) (device); + return Success; +} + +int +ProcQueryPointer(ClientPtr client) +{ + xQueryPointerReply rep; + + WindowPtr pWin, t; + + REQUEST(xResourceReq); + DeviceIntPtr mouse = inputInfo.pointer; + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = SecurityLookupWindow(stuff->id, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.mask = mouse->button->state | inputInfo.keyboard->key->state; + rep.length = 0; + rep.root = (ROOT)->drawable.id; + rep.rootX = sprite.hot.x; + rep.rootY = sprite.hot.y; + rep.child = None; + if (sprite.hot.pScreen == pWin->drawable.pScreen) { + rep.sameScreen = xTrue; + rep.winX = sprite.hot.x - pWin->drawable.x; + rep.winY = sprite.hot.y - pWin->drawable.y; + for (t = sprite.win; t; t = t->parent) + if (t->parent == pWin) { + rep.child = t->drawable.id; + break; + } + } + else { + rep.sameScreen = xFalse; + rep.winX = 0; + rep.winY = 0; + } + + + WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); + + return (Success); +} + +void +InitEvents() +{ + int i; + + sprite.hot.pScreen = sprite.hotPhys.pScreen = (ScreenPtr) NULL; + inputInfo.numDevices = 0; + inputInfo.devices = (DeviceIntPtr) NULL; + inputInfo.off_devices = (DeviceIntPtr) NULL; + inputInfo.keyboard = (DeviceIntPtr) NULL; + inputInfo.pointer = (DeviceIntPtr) NULL; + + memcpy(filters, initialFilters, 128 * sizeof(Mask)); + + if (spriteTraceSize == 0) { + spriteTraceSize = 32; + spriteTrace = malloc(32 * sizeof(WindowPtr)); + if (!spriteTrace) + FatalError("failed to allocate spriteTrace"); + } + spriteTraceGood = 0; + lastEventMask = OwnerGrabButtonMask; + filters[MotionNotify] = PointerMotionMask; + sprite.win = NullWindow; + sprite.current = NullCursor; + sprite.hotLimits.x1 = 0; + sprite.hotLimits.y1 = 0; + sprite.hotLimits.x2 = 0; + sprite.hotLimits.y2 = 0; + sprite.confined = FALSE; + syncEvents.replayDev = (DeviceIntPtr) NULL; + syncEvents.replayWin = NullWindow; + while (syncEvents.pending) { + QdEventPtr next = syncEvents.pending->next; + + free(syncEvents.pending); + syncEvents.pending = next; + } + syncEvents.pendtail = &syncEvents.pending; + syncEvents.playingEvents = FALSE; + syncEvents.time.months = 0; + syncEvents.time.milliseconds = 0; /* hardly matters */ + currentTime.months = 0; + currentTime.milliseconds = GetTimeInMillis(); + lastDeviceEventTime = currentTime; + for (i = 0; i < DNPMCOUNT; i++) { + DontPropagateMasks[i] = 0; + DontPropagateRefCnts[i] = 0; + } +} + +void +CloseDownEvents(void) +{ + free(spriteTrace); + spriteTrace = NULL; + spriteTraceSize = 0; +} + +int +ProcSendEvent(ClientPtr client) +{ + WindowPtr pWin; + + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + + REQUEST(xSendEventReq); + + REQUEST_SIZE_MATCH(xSendEventReq); + + /* The client's event type must be a core event type or one defined by an + extension. */ + + if (!((stuff->event.u.u.type > X_Reply && + stuff->event.u.u.type < LASTEvent) || + (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && + stuff->event.u.u.type < (unsigned) lastEvent))) { + client->errorValue = stuff->event.u.u.type; + return BadValue; + } + if (stuff->event.u.u.type == ClientMessage && + stuff->event.u.u.detail != 8 && + stuff->event.u.u.detail != 16 && stuff->event.u.u.detail != 32) { + client->errorValue = stuff->event.u.u.detail; + return BadValue; + } + if (stuff->eventMask & ~AllEventMasks) { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->destination == PointerWindow) + pWin = sprite.win; + else if (stuff->destination == InputFocus) { + WindowPtr inputFocus = inputInfo.keyboard->focus->win; + + if (inputFocus == NoneWin) + return Success; + + /* If the input focus is PointerRootWin, send the event to where + the pointer is if possible, then perhaps propogate up to root. */ + if (inputFocus == PointerRootWin) + inputFocus = ROOT; + + if (IsParent(inputFocus, sprite.win)) { + effectiveFocus = inputFocus; + pWin = sprite.win; + } + else + effectiveFocus = pWin = inputFocus; + } + else + pWin = SecurityLookupWindow(stuff->destination, client, + SecurityReadAccess); + if (!pWin) + return BadWindow; + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) { + client->errorValue = stuff->propagate; + return BadValue; + } + stuff->event.u.u.type |= 0x80; + if (stuff->propagate) { + for (; pWin; pWin = pWin->parent) { + if (DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, + NullGrab, 0)) + return Success; + if (pWin == effectiveFocus) + return Success; + stuff->eventMask &= ~wDontPropagateMask(pWin); + if (!stuff->eventMask) + break; + } + } + else + (void) DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, + NullGrab, 0); + return Success; +} + +int +ProcUngrabKey(ClientPtr client) +{ + REQUEST(xUngrabKeyReq); + WindowPtr pWin; + + GrabRec tempGrab; + + DeviceIntPtr keybd = inputInfo.keyboard; + + REQUEST_SIZE_MATCH(xUngrabKeyReq); + pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + + if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) || + (stuff->key < keybd->key->curKeySyms.minKeyCode)) + && (stuff->key != AnyKey)) { + client->errorValue = stuff->key; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) { + client->errorValue = stuff->modifiers; + return BadValue; + } + tempGrab.resource = client->clientAsMask; + tempGrab.device = keybd; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = inputInfo.keyboard; + tempGrab.type = KeyPress; + tempGrab.detail.exact = stuff->key; + tempGrab.detail.pMask = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return (BadAlloc); + return (Success); +} + +int +ProcGrabKey(ClientPtr client) +{ + WindowPtr pWin; + + REQUEST(xGrabKeyReq); + GrabPtr grab; + + DeviceIntPtr keybd = inputInfo.keyboard; + + REQUEST_SIZE_MATCH(xGrabKeyReq); + if ((stuff->ownerEvents != xTrue) && (stuff->ownerEvents != xFalse)) { + client->errorValue = stuff->ownerEvents; + return (BadValue); + } + if ((stuff->pointerMode != GrabModeSync) && + (stuff->pointerMode != GrabModeAsync)) { + client->errorValue = stuff->pointerMode; + return BadValue; + } + if ((stuff->keyboardMode != GrabModeSync) && + (stuff->keyboardMode != GrabModeAsync)) { + client->errorValue = stuff->keyboardMode; + return BadValue; + } + if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) || + (stuff->key < keybd->key->curKeySyms.minKeyCode)) + && (stuff->key != AnyKey)) { + client->errorValue = stuff->key; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) { + client->errorValue = stuff->modifiers; + return BadValue; + } + pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + + grab = CreateGrab(client->index, keybd, pWin, + (Mask) (KeyPressMask | KeyReleaseMask), + (Bool) stuff->ownerEvents, (Bool) stuff->keyboardMode, + (Bool) stuff->pointerMode, keybd, stuff->modifiers, + KeyPress, stuff->key, NullWindow, NullCursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(grab); +} + +int +ProcGrabButton(ClientPtr client) +{ + WindowPtr pWin, confineTo; + + REQUEST(xGrabButtonReq); + CursorPtr cursor; + + GrabPtr grab; + + REQUEST_SIZE_MATCH(xGrabButtonReq); + if ((stuff->pointerMode != GrabModeSync) && + (stuff->pointerMode != GrabModeAsync)) { + client->errorValue = stuff->pointerMode; + return BadValue; + } + if ((stuff->keyboardMode != GrabModeSync) && + (stuff->keyboardMode != GrabModeAsync)) { + client->errorValue = stuff->keyboardMode; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) { + client->errorValue = stuff->modifiers; + return BadValue; + } + if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) { + client->errorValue = stuff->ownerEvents; + return BadValue; + } + if (stuff->eventMask & ~PointerGrabMask) { + client->errorValue = stuff->eventMask; + return BadValue; + } + pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + if (stuff->confineTo == None) + confineTo = NullWindow; + else { + confineTo = SecurityLookupWindow(stuff->confineTo, client, + SecurityReadAccess); + if (!confineTo) + return BadWindow; + } + if (stuff->cursor == None) + cursor = NullCursor; + else { + cursor = (CursorPtr) SecurityLookupIDByType(client, stuff->cursor, + RT_CURSOR, + SecurityReadAccess); + if (!cursor) { + client->errorValue = stuff->cursor; + return BadCursor; + } + } + + grab = CreateGrab(client->index, inputInfo.pointer, pWin, + (Mask)stuff->eventMask, (Bool)stuff->ownerEvents, + (Bool)stuff->keyboardMode, (Bool)stuff->pointerMode, + inputInfo.keyboard, stuff->modifiers, ButtonPress, + stuff->button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(grab); +} + +int +ProcUngrabButton(ClientPtr client) +{ + REQUEST(xUngrabButtonReq); + WindowPtr pWin; + + GrabRec tempGrab; + + REQUEST_SIZE_MATCH(xUngrabButtonReq); + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) { + client->errorValue = stuff->modifiers; + return BadValue; + } + pWin = SecurityLookupWindow(stuff->grabWindow, client, SecurityReadAccess); + if (!pWin) + return BadWindow; + tempGrab.resource = client->clientAsMask; + tempGrab.device = inputInfo.pointer; + + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = inputInfo.keyboard; + tempGrab.type = ButtonPress; + tempGrab.detail.exact = stuff->button; + tempGrab.detail.pMask = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return (BadAlloc); + return (Success); +} + +void +DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) +{ + WindowPtr parent; + + DeviceIntPtr mouse = inputInfo.pointer; + + DeviceIntPtr keybd = inputInfo.keyboard; + + FocusClassPtr focus = keybd->focus; + + OtherClientsPtr oc; + + GrabPtr passive; + + /* Deactivate any grabs performed on this window, before making any + input focus changes. */ + + if (mouse->grab && + ((mouse->grab->window == pWin) || (mouse->grab->confineTo == pWin))) + (*mouse->DeactivateGrab) (mouse); + + /* Deactivating a keyboard grab should cause focus events. */ + + if (keybd->grab && (keybd->grab->window == pWin)) + (*keybd->DeactivateGrab) (keybd); + + /* If the focus window is a root window (ie. has no parent) then don't + delete the focus from it. */ + + if ((pWin == focus->win) && (pWin->parent != NullWindow)) { + int focusEventMode = NotifyNormal; + + /* If a grab is in progress, then alter the mode of focus events. */ + + if (keybd->grab) + focusEventMode = NotifyWhileGrabbed; + + switch (focus->revert) { + case RevertToNone: + DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); + focus->win = NoneWin; + focus->traceGood = 0; + break; + case RevertToParent: + parent = pWin; + do { + parent = parent->parent; + focus->traceGood--; + } while (!parent->realized +/* This would be a good protocol change -- windows being reparented + during SaveSet processing would cause the focus to revert to the + nearest enclosing window which will survive the death of the exiting + client, instead of ending up reverting to a dying window and thence + to None + */ +#ifdef NOTDEF + || clients[CLIENT_ID(parent->drawable.id)]->clientGone +#endif + ); + DoFocusEvents(keybd, pWin, parent, focusEventMode); + focus->win = parent; + focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); + focus->win = PointerRootWin; + focus->traceGood = 0; + break; + } + } + + if (mouse->valuator->motionHintWindow == pWin) + mouse->valuator->motionHintWindow = NullWindow; + + if (freeResources) { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + while ((oc = wOtherClients(pWin))) + FreeResource(oc->resource, RT_NONE); + while ((passive = wPassiveGrabs(pWin))) + FreeResource(passive->resource, RT_NONE); + } +} + +/** + * Call this whenever some window at or below pWin has changed geometry + */ +_X_EXPORT void +CheckCursorConfinement(WindowPtr pWin) +{ + GrabPtr grab = inputInfo.pointer->grab; + + WindowPtr confineTo; + + + if (grab && (confineTo = grab->confineTo)) { + if (!BorderSizeNotEmpty(confineTo)) + (*inputInfo.pointer->DeactivateGrab) (inputInfo.pointer); + else if ((pWin == confineTo) || IsParent(pWin, confineTo)) + ConfineCursorToWindow(confineTo, TRUE, TRUE); + } +} + +Mask +EventMaskForClient(WindowPtr pWin, ClientPtr client) +{ + OtherClientsPtr other; + + if (wClient(pWin) == client) + return pWin->eventMask; + for (other = wOtherClients(pWin); other; other = other->next) { + if (SameClient(other, client)) + return other->mask; + } + return 0; +} + +int +ProcRecolorCursor(ClientPtr client) +{ + CursorPtr pCursor; + + int nscr; + + ScreenPtr pscr; + + Bool displayed; + + REQUEST(xRecolorCursorReq); + + REQUEST_SIZE_MATCH(xRecolorCursorReq); + pCursor = (CursorPtr) SecurityLookupIDByType(client, stuff->cursor, + RT_CURSOR, + SecurityWriteAccess); + if (!pCursor) { + client->errorValue = stuff->cursor; + return (BadCursor); + } + + pCursor->foreRed = stuff->foreRed; + pCursor->foreGreen = stuff->foreGreen; + pCursor->foreBlue = stuff->foreBlue; + + pCursor->backRed = stuff->backRed; + pCursor->backGreen = stuff->backGreen; + pCursor->backBlue = stuff->backBlue; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + displayed = (pscr == sprite.hotPhys.pScreen); + (*pscr->RecolorCursor) (pscr, pCursor, + (pCursor == sprite.current) && displayed); + } + return (Success); +} + +_X_EXPORT void +WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) +{ + xEvent eventTo, *eventFrom; + + int i; + + + + if (EventCallback) { + EventInfoRec eventinfo; + + eventinfo.client = pClient; + eventinfo.events = events; + eventinfo.count = count; + CallCallbacks(&EventCallback, (pointer) &eventinfo); + } + if (pClient->swapped) { + for (i = 0; i < count; i++) { + eventFrom = &events[i]; + /* Remember to strip off the leading bit of type in case + this event was sent with "SendEvent." */ + (*EventSwapVector[eventFrom->u.u.type & 0177]) + (eventFrom, &eventTo); + (void) WriteToClient(pClient, sizeof(xEvent), (char *) &eventTo); + } + } + else { + (void) WriteToClient(pClient, count * sizeof(xEvent), (char *) events); + } +} diff --git a/dix/extension.c b/dix/extension.c new file mode 100644 index 0000000..89bb66e --- /dev/null +++ b/dix/extension.c @@ -0,0 +1,404 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "dispatch.h" + +#define EXTENSION_BASE 128 +#define EXTENSION_EVENT_BASE 64 +#define LAST_EVENT 128 +#define LAST_ERROR 255 + +ScreenProcEntry AuxillaryScreenProcs[MAXSCREENS]; + +static ExtensionEntry **extensions = (ExtensionEntry **) NULL; + +int lastEvent = EXTENSION_EVENT_BASE; + +static int lastError = FirstExtensionError; + +static unsigned int NumExtensions = 0; + +extern int extensionPrivateLen; + +extern unsigned *extensionPrivateSizes; + +extern unsigned totalExtensionSize; + +static void +InitExtensionPrivates(ExtensionEntry * ext) +{ + char *ptr; + + DevUnion *ppriv; + + unsigned *sizes; + + unsigned size; + + int i; + + if (totalExtensionSize == sizeof(ExtensionEntry)) + ppriv = (DevUnion *) NULL; + else + ppriv = (DevUnion *) (ext + 1); + + ext->devPrivates = ppriv; + sizes = extensionPrivateSizes; + ptr = (char *) (ppriv + extensionPrivateLen); + for (i = extensionPrivateLen; --i >= 0; ppriv++, sizes++) { + if ((size = *sizes)) { + ppriv->ptr = (pointer) ptr; + ptr += size; + } + else + ppriv->ptr = (pointer) NULL; + } +} + +_X_EXPORT ExtensionEntry * +AddExtension(char *name, int NumEvents, int NumErrors, + int (*MainProc) (ClientPtr c1), + int (*SwappedMainProc) (ClientPtr c2), + void (*CloseDownProc) (ExtensionEntry * e), + unsigned short (*MinorOpcodeProc) (ClientPtr c3)) +{ + int i; + + ExtensionEntry *ext, **newexts; + + if (!MainProc || !SwappedMainProc || !CloseDownProc || !MinorOpcodeProc) + return ((ExtensionEntry *) NULL); + if ((lastEvent + NumEvents > LAST_EVENT) || + (unsigned) (lastError + NumErrors > LAST_ERROR)) + return ((ExtensionEntry *) NULL); + + ext = malloc(totalExtensionSize); + if (!ext) + return ((ExtensionEntry *) NULL); + bzero(ext, totalExtensionSize); + InitExtensionPrivates(ext); + ext->name = malloc(strlen(name) + 1); + ext->num_aliases = 0; + ext->aliases = (char **) NULL; + if (!ext->name) { + free(ext); + return ((ExtensionEntry *) NULL); + } + strcpy(ext->name, name); + i = NumExtensions; + newexts = (ExtensionEntry **) realloc(extensions, + (i + 1) * sizeof(ExtensionEntry *)); + if (!newexts) { + free(ext->name); + free(ext); + return ((ExtensionEntry *) NULL); + } + NumExtensions++; + extensions = newexts; + extensions[i] = ext; + ext->index = i; + ext->base = i + EXTENSION_BASE; + ext->CloseDown = CloseDownProc; + ext->MinorOpcode = MinorOpcodeProc; + ProcVector[i + EXTENSION_BASE] = MainProc; + SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc; + if (NumEvents) { + ext->eventBase = lastEvent; + ext->eventLast = lastEvent + NumEvents; + lastEvent += NumEvents; + } + else { + ext->eventBase = 0; + ext->eventLast = 0; + } + if (NumErrors) { + ext->errorBase = lastError; + ext->errorLast = lastError + NumErrors; + lastError += NumErrors; + } + else { + ext->errorBase = 0; + ext->errorLast = 0; + } + + return (ext); +} + +static int +FindExtension(char *extname, int len) +{ + int i, j; + + for (i = 0; i < NumExtensions; i++) { + if ((strlen(extensions[i]->name) == len) && + !strncmp(extname, extensions[i]->name, len)) + break; + for (j = extensions[i]->num_aliases; --j >= 0;) { + if ((strlen(extensions[i]->aliases[j]) == len) && + !strncmp(extname, extensions[i]->aliases[j], len)) + break; + } + if (j >= 0) + break; + } + return ((i == NumExtensions) ? -1 : i); +} + +_X_EXPORT void +DeclareExtensionSecurity(char *extname, Bool secure) +{ +} + +_X_EXPORT unsigned short +StandardMinorOpcode(ClientPtr client) +{ + return ((xReq *) client->requestBuffer)->data; +} + +_X_EXPORT unsigned short +MinorOpcodeOfRequest(ClientPtr client) +{ + unsigned char major; + + major = ((xReq *) client->requestBuffer)->reqType; + if (major < EXTENSION_BASE) + return 0; + major -= EXTENSION_BASE; + if (major >= NumExtensions) + return 0; + return (*extensions[major]->MinorOpcode) (client); +} + +void +CloseDownExtensions() +{ + int i, j; + + for (i = NumExtensions - 1; i >= 0; i--) { + (*extensions[i]->CloseDown) (extensions[i]); + NumExtensions = i; + free(extensions[i]->name); + for (j = extensions[i]->num_aliases; --j >= 0;) + free(extensions[i]->aliases[j]); + free(extensions[i]->aliases); + free(extensions[i]); + } + free(extensions); + extensions = (ExtensionEntry **) NULL; + lastEvent = EXTENSION_EVENT_BASE; + lastError = FirstExtensionError; + for (i = 0; i < MAXSCREENS; i++) { + ScreenProcEntry *spentry = &AuxillaryScreenProcs[i]; + + while (spentry->num) { + spentry->num--; + free(spentry->procList[spentry->num].name); + } + free(spentry->procList); + spentry->procList = (ProcEntryPtr) NULL; + } +} + +int +ProcQueryExtension(ClientPtr client) +{ + xQueryExtensionReply reply = {0}; + + int i; + + REQUEST(xQueryExtensionReq); + + REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); + + reply.type = X_Reply; + reply.length = 0; + reply.major_opcode = 0; + reply.sequenceNumber = client->sequence; + + if (!NumExtensions) + reply.present = xFalse; + else { + i = FindExtension((char *) &stuff[1], stuff->nbytes); + if (i < 0 + ) + reply.present = xFalse; + else { + reply.present = xTrue; + reply.major_opcode = extensions[i]->base; + reply.first_event = extensions[i]->eventBase; + reply.first_error = extensions[i]->errorBase; + } + } + WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply); + return (client->noClientException); +} + +int +ProcListExtensions(ClientPtr client) +{ + xListExtensionsReply reply = {0}; + + char *bufptr, *buffer; + + int total_length = 0; + + REQUEST_SIZE_MATCH(xReq); + + reply.type = X_Reply; + reply.nExtensions = 0; + reply.length = 0; + reply.sequenceNumber = client->sequence; + buffer = NULL; + + if (NumExtensions) { + int i, j; + + for (i = 0; i < NumExtensions; i++) { + total_length += strlen(extensions[i]->name) + 1; + reply.nExtensions += 1 + extensions[i]->num_aliases; + for (j = extensions[i]->num_aliases; --j >= 0;) + total_length += strlen(extensions[i]->aliases[j]) + 1; + } + reply.length = (total_length + 3) >> 2; + buffer = bufptr = (char *) ALLOCATE_LOCAL(total_length); + if (!buffer) + return (BadAlloc); + for (i = 0; i < NumExtensions; i++) { + int len; + + *bufptr++ = len = strlen(extensions[i]->name); + memmove(bufptr, extensions[i]->name, len); + bufptr += len; + for (j = extensions[i]->num_aliases; --j >= 0;) { + *bufptr++ = len = strlen(extensions[i]->aliases[j]); + memmove(bufptr, extensions[i]->aliases[j], len); + bufptr += len; + } + } + } + WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply); + if (reply.length) { + WriteToClient(client, total_length, buffer); + DEALLOCATE_LOCAL(buffer); + } + return (client->noClientException); +} + +ExtensionLookupProc +LookupProc(char *name, GCPtr pGC) +{ + int i; + + ScreenProcEntry *spentry; + + spentry = &AuxillaryScreenProcs[pGC->pScreen->myNum]; + if (spentry->num) { + for (i = 0; i < spentry->num; i++) + if (strcmp(name, spentry->procList[i].name) == 0) + return (spentry->procList[i].proc); + } + return (ExtensionLookupProc) NULL; +} + +Bool +RegisterProc(char *name, GC * pGC, ExtensionLookupProc proc) +{ + return RegisterScreenProc(name, pGC->pScreen, proc); +} + +Bool +RegisterScreenProc(char *name, ScreenPtr pScreen, ExtensionLookupProc proc) +{ + ScreenProcEntry *spentry; + + ProcEntryPtr procEntry = (ProcEntryPtr) NULL; + + char *newname; + + int i; + + spentry = &AuxillaryScreenProcs[pScreen->myNum]; + /* first replace duplicates */ + if (spentry->num) { + for (i = 0; i < spentry->num; i++) + if (strcmp(name, spentry->procList[i].name) == 0) { + procEntry = &spentry->procList[i]; + break; + } + } + if (procEntry) + procEntry->proc = proc; + else { + newname = malloc(strlen(name) + 1); + if (!newname) + return FALSE; + procEntry = (ProcEntryPtr) + realloc(spentry->procList, + sizeof(ProcEntryRec) * (spentry->num + 1)); + if (!procEntry) { + free(newname); + return FALSE; + } + spentry->procList = procEntry; + procEntry += spentry->num; + procEntry->name = newname; + strcpy(newname, name); + procEntry->proc = proc; + spentry->num++; + } + return TRUE; +} diff --git a/dix/ffs.c b/dix/ffs.c new file mode 100644 index 0000000..1e75076 --- /dev/null +++ b/dix/ffs.c @@ -0,0 +1,39 @@ +/* + +Copyright 1996, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABIL- +ITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization from +The Open Group. + +*/ + +int +ffs(int i) +{ + int j; + + if (i == 0) + return 0; + for (j = 1; (i & 1) == 0; j++) + i >>= 1; + return j; +} diff --git a/dix/gc.c b/dix/gc.c new file mode 100644 index 0000000..2e0e051 --- /dev/null +++ b/dix/gc.c @@ -0,0 +1,1275 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include "misc.h" +#include "resource.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "dixfontstr.h" +#include "scrnintstr.h" +#include "region.h" + +#include "dix.h" +#include + +extern XID clientErrorValue; + +extern FontPtr defaultFont; + +static Bool CreateDefaultTile(GCPtr pGC); + +static unsigned char DefaultDash[2] = { 4, 4 }; + +_X_EXPORT void +ValidateGC(DrawablePtr pDraw, GC * pGC) +{ + (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw); + pGC->stateChanges = 0; + pGC->serialNumber = pDraw->serialNumber; +} + +/* dixChangeGC(client, pGC, mask, pC32, pUnion) + * + * This function was created as part of the Security extension + * implementation. The client performing the gc change must be passed so + * that access checks can be performed on any tiles, stipples, or fonts + * that are specified. ddxen can call this too; they should normally + * pass NullClient for the client since any access checking should have + * already been done at a higher level. + * + * Since we had to create a new function anyway, we decided to change the + * way the list of gc values is passed to eliminate the compiler warnings + * caused by the DoChangeGC interface. You can pass the values via pC32 + * or pUnion, but not both; one of them must be NULL. If you don't need + * to pass any pointers, you can use either one: + * + * example calling dixChangeGC using pC32 parameter + * + * CARD32 v[2]; + * v[0] = foreground; + * v[1] = background; + * dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL); + * + * example calling dixChangeGC using pUnion parameter; + * same effect as above + * + * ChangeGCVal v[2]; + * v[0].val = foreground; + * v[1].val = background; + * dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v); + * + * However, if you need to pass a pointer to a pixmap or font, you MUST + * use the pUnion parameter. + * + * example calling dixChangeGC passing pointers in the value list + * v[1].ptr is a pointer to a pixmap + * + * ChangeGCVal v[2]; + * v[0].val = FillTiled; + * v[1].ptr = pPixmap; + * dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v); + * + * Note: we could have gotten by with just the pUnion parameter, but on + * 64 bit machines that would have forced us to copy the value list that + * comes in the ChangeGC request. + * + * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this + * is far too many changes to consider at this time, so we've only + * changed the ones that caused compiler warnings. New code should use + * dixChangeGC. + * + * dpw + */ + +#define NEXTVAL(_type, _var) { \ + if (pC32) _var = (_type)*pC32++; \ + else { \ + _var = (_type)(pUnion->val); pUnion++; \ + } \ + } + +#define NEXT_PTR(_type, _var) { \ + assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; } + +_X_EXPORT int +dixChangeGC(ClientPtr client, register GC * pGC, register BITS32 mask, + CARD32 *pC32, ChangeGCValPtr pUnion) +{ + BITS32 index2; + + int error = 0; + + PixmapPtr pPixmap; + + BITS32 maskQ; + + assert((pC32 && !pUnion) || (!pC32 && pUnion)); + pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; + + maskQ = mask; /* save these for when we walk the GCque */ + while (mask && !error) { + index2 = (BITS32) lowbit(mask); + mask &= ~index2; + pGC->stateChanges |= index2; + switch (index2) { + case GCFunction: + { + CARD8 newalu; + + NEXTVAL(CARD8, newalu); + + if (newalu <= GXset) + pGC->alu = newalu; + else { + clientErrorValue = newalu; + error = BadValue; + } + break; + } + case GCPlaneMask: + NEXTVAL(unsigned long, pGC->planemask); + + break; + case GCForeground: + NEXTVAL(unsigned long, pGC->fgPixel); + + /* + * this is for CreateGC + */ + if (!pGC->tileIsPixel && !pGC->tile.pixmap) { + pGC->tileIsPixel = TRUE; + pGC->tile.pixel = pGC->fgPixel; + } + break; + case GCBackground: + NEXTVAL(unsigned long, pGC->bgPixel); + + break; + case GCLineWidth: /* ??? line width is a CARD16 */ + NEXTVAL(CARD16, pGC->lineWidth); + + break; + case GCLineStyle: + { + unsigned int newlinestyle; + + NEXTVAL(unsigned int, newlinestyle); + + if (newlinestyle <= LineDoubleDash) + pGC->lineStyle = newlinestyle; + else { + clientErrorValue = newlinestyle; + error = BadValue; + } + break; + } + case GCCapStyle: + { + unsigned int newcapstyle; + + NEXTVAL(unsigned int, newcapstyle); + + if (newcapstyle <= CapProjecting) + pGC->capStyle = newcapstyle; + else { + clientErrorValue = newcapstyle; + error = BadValue; + } + break; + } + case GCJoinStyle: + { + unsigned int newjoinstyle; + + NEXTVAL(unsigned int, newjoinstyle); + + if (newjoinstyle <= JoinBevel) + pGC->joinStyle = newjoinstyle; + else { + clientErrorValue = newjoinstyle; + error = BadValue; + } + break; + } + case GCFillStyle: + { + unsigned int newfillstyle; + + NEXTVAL(unsigned int, newfillstyle); + + if (newfillstyle <= FillOpaqueStippled) + pGC->fillStyle = newfillstyle; + else { + clientErrorValue = newfillstyle; + error = BadValue; + } + break; + } + case GCFillRule: + { + unsigned int newfillrule; + + NEXTVAL(unsigned int, newfillrule); + + if (newfillrule <= WindingRule) + pGC->fillRule = newfillrule; + else { + clientErrorValue = newfillrule; + error = BadValue; + } + break; + } + case GCTile: + { + XID newpix = 0; + + if (pUnion) { + NEXT_PTR(PixmapPtr, pPixmap); + } + else { + NEXTVAL(XID, newpix); + + pPixmap = (PixmapPtr) SecurityLookupIDByType(client, + newpix, RT_PIXMAP, + SecurityReadAccess); + } + if (pPixmap) { + if ((pPixmap->drawable.depth != pGC->depth) || + (pPixmap->drawable.pScreen != pGC->pScreen)) { + error = BadMatch; + } + else { + pPixmap->refcnt++; + if (!pGC->tileIsPixel) + (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap); + pGC->tileIsPixel = FALSE; + pGC->tile.pixmap = pPixmap; + } + } + else { + clientErrorValue = newpix; + error = BadPixmap; + } + break; + } + case GCStipple: + { + XID newstipple = 0; + + if (pUnion) { + NEXT_PTR(PixmapPtr, pPixmap); + } + else { + NEXTVAL(XID, newstipple) + pPixmap = (PixmapPtr) SecurityLookupIDByType(client, + newstipple, + RT_PIXMAP, + SecurityReadAccess); + } + if (pPixmap) { + if ((pPixmap->drawable.depth != 1) || + (pPixmap->drawable.pScreen != pGC->pScreen)) { + error = BadMatch; + } + else { + pPixmap->refcnt++; + if (pGC->stipple) + (*pGC->pScreen->DestroyPixmap) (pGC->stipple); + pGC->stipple = pPixmap; + } + } + else { + clientErrorValue = newstipple; + error = BadPixmap; + } + break; + } + case GCTileStipXOrigin: + NEXTVAL(INT16, pGC->patOrg.x); + + break; + case GCTileStipYOrigin: + NEXTVAL(INT16, pGC->patOrg.y); + + break; + case GCFont: + { + FontPtr pFont; + + XID newfont = 0; + + if (pUnion) { + NEXT_PTR(FontPtr, pFont); + } + else { + NEXTVAL(XID, newfont) + pFont = (FontPtr) SecurityLookupIDByType(client, newfont, + RT_FONT, + SecurityReadAccess); + } + if (pFont) { + pFont->refcnt++; + if (pGC->font) + CloseFont(pGC->font, (Font) 0); + pGC->font = pFont; + } + else { + clientErrorValue = newfont; + error = BadFont; + } + break; + } + case GCSubwindowMode: + { + unsigned int newclipmode; + + NEXTVAL(unsigned int, newclipmode); + + if (newclipmode <= IncludeInferiors) + pGC->subWindowMode = newclipmode; + else { + clientErrorValue = newclipmode; + error = BadValue; + } + break; + } + case GCGraphicsExposures: + { + unsigned int newge; + + NEXTVAL(unsigned int, newge); + + if (newge <= xTrue) + pGC->graphicsExposures = newge; + else { + clientErrorValue = newge; + error = BadValue; + } + break; + } + case GCClipXOrigin: + NEXTVAL(INT16, pGC->clipOrg.x); + + break; + case GCClipYOrigin: + NEXTVAL(INT16, pGC->clipOrg.y); + + break; + case GCClipMask: + { + Pixmap pid = 0; + + int clipType = 0; + + if (pUnion) { + NEXT_PTR(PixmapPtr, pPixmap); + } + else { + NEXTVAL(Pixmap, pid) + if (pid == None) { + clipType = CT_NONE; + pPixmap = NullPixmap; + } + else + pPixmap = (PixmapPtr) SecurityLookupIDByType(client, + pid, RT_PIXMAP, + SecurityReadAccess); + } + + if (pPixmap) { + if ((pPixmap->drawable.depth != 1) || + (pPixmap->drawable.pScreen != pGC->pScreen)) { + error = BadMatch; + } + else { + clipType = CT_PIXMAP; + pPixmap->refcnt++; + } + } + else if (!pUnion && (pid != None)) { + clientErrorValue = pid; + error = BadPixmap; + } + if (error == Success) { + (*pGC->funcs->ChangeClip) (pGC, clipType, (pointer) pPixmap, 0); + } + break; + } + case GCDashOffset: + NEXTVAL(INT16, pGC->dashOffset); + + break; + case GCDashList: + { + CARD8 newdash; + + NEXTVAL(CARD8, newdash); + + if (newdash == 4) { + if (pGC->dash != DefaultDash) { + free(pGC->dash); + pGC->numInDashList = 2; + pGC->dash = DefaultDash; + } + } + else if (newdash != 0) { + unsigned char *dash; + + dash = malloc(2 * sizeof(unsigned char)); + if (dash) { + if (pGC->dash != DefaultDash) + free(pGC->dash); + pGC->numInDashList = 2; + pGC->dash = dash; + dash[0] = newdash; + dash[1] = newdash; + } + else + error = BadAlloc; + } + else { + clientErrorValue = newdash; + error = BadValue; + } + break; + } + case GCArcMode: + { + unsigned int newarcmode; + + NEXTVAL(unsigned int, newarcmode); + + if (newarcmode <= ArcPieSlice) + pGC->arcMode = newarcmode; + else { + clientErrorValue = newarcmode; + error = BadValue; + } + break; + } + default: + clientErrorValue = maskQ; + error = BadValue; + break; + } + } /* end while mask && !error */ + + if (pGC->fillStyle == FillTiled && pGC->tileIsPixel) { + if (!CreateDefaultTile(pGC)) { + pGC->fillStyle = FillSolid; + error = BadAlloc; + } + } + (*pGC->funcs->ChangeGC) (pGC, maskQ); + return error; +} + +#undef NEXTVAL +#undef NEXT_PTR + +/* Publically defined entry to ChangeGC. Just calls dixChangeGC and tells + * it that all of the entries are constants or IDs */ +_X_EXPORT int +ChangeGC(register GC * pGC, register BITS32 mask, XID *pval) +{ + return (dixChangeGC(NullClient, pGC, mask, pval, NULL)); +} + +/* DoChangeGC(pGC, mask, pval, fPointer) + mask is a set of bits indicating which values to change. + pval contains an appropriate value for each mask. + fPointer is true if the values for tiles, stipples, fonts or clipmasks + are pointers instead of IDs. Note: if you are passing pointers you + MUST declare the array of values as type pointer! Other data types + may not be large enough to hold pointers on some machines. Yes, + this means you have to cast to (XID *) when you pass the array to + DoChangeGC. Similarly, if you are not passing pointers (fPointer = 0) you + MUST declare the array as type XID (not unsigned long!), or again the wrong + size data type may be used. To avoid this cruftiness, use dixChangeGC + above. + + if there is an error, the value is marked as changed + anyway, which is probably wrong, but infrequent. + +NOTE: + all values sent over the protocol for ChangeGC requests are +32 bits long +*/ +_X_EXPORT int +DoChangeGC(register GC * pGC, register BITS32 mask, XID *pval, int fPointer) +{ + if (fPointer) + /* XXX might be a problem on 64 bit big-endian servers */ + return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr) pval); + else + return dixChangeGC(NullClient, pGC, mask, pval, NULL); +} + +/* CreateGC(pDrawable, mask, pval, pStatus) + creates a default GC for the given drawable, using mask to fill + in any non-default values. + Returns a pointer to the new GC on success, NULL otherwise. + returns status of non-default fields in pStatus +BUG: + should check for failure to create default tile + +*/ + +static GCPtr +AllocateGC(ScreenPtr pScreen) +{ + GCPtr pGC; + + char *ptr; + + DevUnion *ppriv; + + unsigned *sizes; + + unsigned size; + + int i; + + pGC = malloc(pScreen->totalGCSize); + if (pGC) { + ppriv = (DevUnion *) (pGC + 1); + pGC->devPrivates = ppriv; + sizes = pScreen->GCPrivateSizes; + ptr = (char *) (ppriv + pScreen->GCPrivateLen); + for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++) { + if ((size = *sizes)) { + ppriv->ptr = (pointer) ptr; + ptr += size; + } + else + ppriv->ptr = (pointer) NULL; + } + } + return pGC; +} + +_X_EXPORT GCPtr +CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus) +{ + GCPtr pGC; + + pGC = AllocateGC(pDrawable->pScreen); + if (!pGC) { + *pStatus = BadAlloc; + return (GCPtr) NULL; + } + + pGC->pScreen = pDrawable->pScreen; + pGC->depth = pDrawable->depth; + pGC->alu = GXcopy; /* dst <- src */ + pGC->planemask = ~0; + pGC->serialNumber = GC_CHANGE_SERIAL_BIT; + pGC->funcs = 0; + + pGC->fgPixel = 0; + pGC->bgPixel = 1; + pGC->lineWidth = 0; + pGC->lineStyle = LineSolid; + pGC->capStyle = CapButt; + pGC->joinStyle = JoinMiter; + pGC->fillStyle = FillSolid; + pGC->fillRule = EvenOddRule; + pGC->arcMode = ArcPieSlice; + if (mask & GCForeground) { + /* + * magic special case -- ChangeGC checks for this condition + * and snags the Foreground value to create a pseudo default-tile + */ + pGC->tileIsPixel = FALSE; + pGC->tile.pixmap = NullPixmap; + } + else { + pGC->tileIsPixel = TRUE; + pGC->tile.pixel = 0; + } + + pGC->patOrg.x = 0; + pGC->patOrg.y = 0; + pGC->subWindowMode = ClipByChildren; + pGC->graphicsExposures = TRUE; + pGC->clipOrg.x = 0; + pGC->clipOrg.y = 0; + pGC->clientClipType = CT_NONE; + pGC->clientClip = (pointer) NULL; + pGC->numInDashList = 2; + pGC->dash = DefaultDash; + pGC->dashOffset = 0; + pGC->lastWinOrg.x = 0; + pGC->lastWinOrg.y = 0; + + /* use the default font and stipple */ + pGC->font = defaultFont; + defaultFont->refcnt++; + pGC->stipple = pGC->pScreen->PixmapPerDepth[0]; + pGC->stipple->refcnt++; + + pGC->stateChanges = (1 << (GCLastBit + 1)) - 1; + if (!(*pGC->pScreen->CreateGC) (pGC)) + *pStatus = BadAlloc; + else if (mask) + *pStatus = ChangeGC(pGC, mask, pval); + else + *pStatus = Success; + if (*pStatus != Success) { + if (!pGC->tileIsPixel && !pGC->tile.pixmap) + pGC->tileIsPixel = TRUE; /* undo special case */ + FreeGC(pGC, (XID) 0); + pGC = (GCPtr) NULL; + } + + return (pGC); +} + +static Bool +CreateDefaultTile(GCPtr pGC) +{ + XID tmpval[3]; + + PixmapPtr pTile; + + GCPtr pgcScratch; + + xRectangle rect; + + CARD16 w, h; + + w = 1; + h = 1; + (*pGC->pScreen->QueryBestSize) (TileShape, &w, &h, pGC->pScreen); + pTile = (PixmapPtr) + (*pGC->pScreen->CreatePixmap) (pGC->pScreen, w, h, pGC->depth); + pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen); + if (!pTile || !pgcScratch) { + if (pTile) + (*pTile->drawable.pScreen->DestroyPixmap) (pTile); + if (pgcScratch) + FreeScratchGC(pgcScratch); + return FALSE; + } + tmpval[0] = GXcopy; + tmpval[1] = pGC->tile.pixel; + tmpval[2] = FillSolid; + (void) ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle, + tmpval); + ValidateGC((DrawablePtr) pTile, pgcScratch); + rect.x = 0; + rect.y = 0; + rect.width = w; + rect.height = h; + (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pTile, pgcScratch, 1, + &rect); + /* Always remember to free the scratch graphics context after use. */ + FreeScratchGC(pgcScratch); + + pGC->tileIsPixel = FALSE; + pGC->tile.pixmap = pTile; + return TRUE; +} + +_X_EXPORT int +CopyGC(register GC * pgcSrc, register GC * pgcDst, register BITS32 mask) +{ + BITS32 index2; + + BITS32 maskQ; + + int error = 0; + + if (pgcSrc == pgcDst) + return Success; + pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT; + pgcDst->stateChanges |= mask; + maskQ = mask; + while (mask) { + index2 = (BITS32) lowbit(mask); + mask &= ~index2; + switch (index2) { + case GCFunction: + pgcDst->alu = pgcSrc->alu; + break; + case GCPlaneMask: + pgcDst->planemask = pgcSrc->planemask; + break; + case GCForeground: + pgcDst->fgPixel = pgcSrc->fgPixel; + break; + case GCBackground: + pgcDst->bgPixel = pgcSrc->bgPixel; + break; + case GCLineWidth: + pgcDst->lineWidth = pgcSrc->lineWidth; + break; + case GCLineStyle: + pgcDst->lineStyle = pgcSrc->lineStyle; + break; + case GCCapStyle: + pgcDst->capStyle = pgcSrc->capStyle; + break; + case GCJoinStyle: + pgcDst->joinStyle = pgcSrc->joinStyle; + break; + case GCFillStyle: + pgcDst->fillStyle = pgcSrc->fillStyle; + break; + case GCFillRule: + pgcDst->fillRule = pgcSrc->fillRule; + break; + case GCTile: + { + if (EqualPixUnion(pgcDst->tileIsPixel, + pgcDst->tile, + pgcSrc->tileIsPixel, pgcSrc->tile)) { + break; + } + if (!pgcDst->tileIsPixel) + (*pgcDst->pScreen->DestroyPixmap) (pgcDst->tile.pixmap); + pgcDst->tileIsPixel = pgcSrc->tileIsPixel; + pgcDst->tile = pgcSrc->tile; + if (!pgcDst->tileIsPixel) + pgcDst->tile.pixmap->refcnt++; + break; + } + case GCStipple: + { + if (pgcDst->stipple == pgcSrc->stipple) + break; + if (pgcDst->stipple) + (*pgcDst->pScreen->DestroyPixmap) (pgcDst->stipple); + pgcDst->stipple = pgcSrc->stipple; + if (pgcDst->stipple) + pgcDst->stipple->refcnt++; + break; + } + case GCTileStipXOrigin: + pgcDst->patOrg.x = pgcSrc->patOrg.x; + break; + case GCTileStipYOrigin: + pgcDst->patOrg.y = pgcSrc->patOrg.y; + break; + case GCFont: + if (pgcDst->font == pgcSrc->font) + break; + if (pgcDst->font) + CloseFont(pgcDst->font, (Font) 0); + if ((pgcDst->font = pgcSrc->font) != NullFont) + (pgcDst->font)->refcnt++; + break; + case GCSubwindowMode: + pgcDst->subWindowMode = pgcSrc->subWindowMode; + break; + case GCGraphicsExposures: + pgcDst->graphicsExposures = pgcSrc->graphicsExposures; + break; + case GCClipXOrigin: + pgcDst->clipOrg.x = pgcSrc->clipOrg.x; + break; + case GCClipYOrigin: + pgcDst->clipOrg.y = pgcSrc->clipOrg.y; + break; + case GCClipMask: + (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc); + break; + case GCDashOffset: + pgcDst->dashOffset = pgcSrc->dashOffset; + break; + case GCDashList: + if (pgcSrc->dash == DefaultDash) { + if (pgcDst->dash != DefaultDash) { + free(pgcDst->dash); + pgcDst->numInDashList = pgcSrc->numInDashList; + pgcDst->dash = pgcSrc->dash; + } + } + else { + unsigned char *dash; + + unsigned int i; + + dash = malloc(pgcSrc->numInDashList * + sizeof(unsigned char)); + if (dash) { + if (pgcDst->dash != DefaultDash) + free(pgcDst->dash); + pgcDst->numInDashList = pgcSrc->numInDashList; + pgcDst->dash = dash; + for (i = 0; i < pgcSrc->numInDashList; i++) + dash[i] = pgcSrc->dash[i]; + } + else + error = BadAlloc; + } + break; + case GCArcMode: + pgcDst->arcMode = pgcSrc->arcMode; + break; + default: + clientErrorValue = maskQ; + error = BadValue; + break; + } + } + if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel) { + if (!CreateDefaultTile(pgcDst)) { + pgcDst->fillStyle = FillSolid; + error = BadAlloc; + } + } + (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst); + return error; +} + +/** + * does the diX part of freeing the characteristics in the GC. + * + * \param value must conform to DeleteType + */ +_X_EXPORT int +FreeGC(pointer value, XID gid) +{ + GCPtr pGC = (GCPtr) value; + + CloseFont(pGC->font, (Font) 0); + (*pGC->funcs->DestroyClip) (pGC); + + if (!pGC->tileIsPixel) + (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap); + if (pGC->stipple) + (*pGC->pScreen->DestroyPixmap) (pGC->stipple); + + (*pGC->funcs->DestroyGC) (pGC); + if (pGC->dash != DefaultDash) + free(pGC->dash); + free(pGC); + return (Success); +} + +void +SetGCMask(GCPtr pGC, Mask selectMask, Mask newDataMask) +{ + pGC->stateChanges = (~selectMask & pGC->stateChanges) | + (selectMask & newDataMask); + if (selectMask & newDataMask) + pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; +} + +/* CreateScratchGC(pScreen, depth) + like CreateGC, but doesn't do the default tile or stipple, +since we can't create them without already having a GC. any code +using the tile or stipple has to set them explicitly anyway, +since the state of the scratch gc is unknown. This is OK +because ChangeGC() has to be able to deal with NULL tiles and +stipples anyway (in case the CreateGC() call has provided a +value for them -- we can't set the default tile until the +client-supplied attributes are installed, since the fgPixel +is what fills the default tile. (maybe this comment should +go with CreateGC() or ChangeGC().) +*/ + +_X_EXPORT GCPtr +CreateScratchGC(ScreenPtr pScreen, unsigned depth) +{ + GCPtr pGC; + + pGC = AllocateGC(pScreen); + if (!pGC) + return (GCPtr) NULL; + + pGC->pScreen = pScreen; + pGC->depth = depth; + pGC->alu = GXcopy; /* dst <- src */ + pGC->planemask = ~0; + pGC->serialNumber = 0; + + pGC->fgPixel = 0; + pGC->bgPixel = 1; + pGC->lineWidth = 0; + pGC->lineStyle = LineSolid; + pGC->capStyle = CapButt; + pGC->joinStyle = JoinMiter; + pGC->fillStyle = FillSolid; + pGC->fillRule = EvenOddRule; + pGC->arcMode = ArcPieSlice; + pGC->font = defaultFont; + if (pGC->font) /* necessary, because open of default font could fail */ + pGC->font->refcnt++; + pGC->tileIsPixel = TRUE; + pGC->tile.pixel = 0; + pGC->stipple = NullPixmap; + pGC->patOrg.x = 0; + pGC->patOrg.y = 0; + pGC->subWindowMode = ClipByChildren; + pGC->graphicsExposures = TRUE; + pGC->clipOrg.x = 0; + pGC->clipOrg.y = 0; + pGC->clientClipType = CT_NONE; + pGC->dashOffset = 0; + pGC->numInDashList = 2; + pGC->dash = DefaultDash; + pGC->lastWinOrg.x = 0; + pGC->lastWinOrg.y = 0; + + pGC->stateChanges = (1 << (GCLastBit + 1)) - 1; + if (!(*pScreen->CreateGC) (pGC)) { + FreeGC(pGC, (XID) 0); + pGC = (GCPtr) NULL; + } + return pGC; +} + +void +FreeGCperDepth(int screenNum) +{ + int i; + + ScreenPtr pScreen; + + GCPtr *ppGC; + + pScreen = screenInfo.screens[screenNum]; + ppGC = pScreen->GCperDepth; + + for (i = 0; i <= pScreen->numDepths; i++) + (void) FreeGC(ppGC[i], (XID) 0); + pScreen->rgf = ~0L; +} + +Bool +CreateGCperDepth(int screenNum) +{ + int i; + + ScreenPtr pScreen; + + DepthPtr pDepth; + + GCPtr *ppGC; + + pScreen = screenInfo.screens[screenNum]; + pScreen->rgf = 0; + ppGC = pScreen->GCperDepth; + /* do depth 1 separately because it's not included in list */ + if (!(ppGC[0] = CreateScratchGC(pScreen, 1))) + return FALSE; + ppGC[0]->graphicsExposures = FALSE; + /* Make sure we don't overflow GCperDepth[] */ + if (pScreen->numDepths > MAXFORMATS) + return FALSE; + + pDepth = pScreen->allowedDepths; + for (i = 0; i < pScreen->numDepths; i++, pDepth++) { + if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) { + for (; i >= 0; i--) + (void) FreeGC(ppGC[i], (XID) 0); + return FALSE; + } + ppGC[i + 1]->graphicsExposures = FALSE; + } + return TRUE; +} + +Bool +CreateDefaultStipple(int screenNum) +{ + ScreenPtr pScreen; + + XID tmpval[3]; + + xRectangle rect; + + CARD16 w, h; + + GCPtr pgcScratch; + + pScreen = screenInfo.screens[screenNum]; + + w = 16; + h = 16; + (*pScreen->QueryBestSize) (StippleShape, &w, &h, pScreen); + if (!(pScreen->PixmapPerDepth[0] = + (*pScreen->CreatePixmap) (pScreen, w, h, 1))) + return FALSE; + /* fill stipple with 1 */ + tmpval[0] = GXcopy; + tmpval[1] = 1; + tmpval[2] = FillSolid; + pgcScratch = GetScratchGC(1, pScreen); + if (!pgcScratch) { + (*pScreen->DestroyPixmap) (pScreen->PixmapPerDepth[0]); + return FALSE; + } + (void) ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle, + tmpval); + ValidateGC((DrawablePtr) pScreen->PixmapPerDepth[0], pgcScratch); + rect.x = 0; + rect.y = 0; + rect.width = w; + rect.height = h; + (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->PixmapPerDepth[0], + pgcScratch, 1, &rect); + FreeScratchGC(pgcScratch); + return TRUE; +} + +void +FreeDefaultStipple(int screenNum) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + + (*pScreen->DestroyPixmap) (pScreen->PixmapPerDepth[0]); +} + +_X_EXPORT int +SetDashes(register GCPtr pGC, unsigned offset, unsigned ndash, + unsigned char *pdash) +{ + long i; + + unsigned char *p, *indash; + + BITS32 maskQ = 0; + + i = ndash; + p = pdash; + while (i--) { + if (!*p++) { + /* dash segment must be > 0 */ + clientErrorValue = 0; + return BadValue; + } + } + + if (ndash & 1) + p = malloc(2 * ndash * sizeof(unsigned char)); + else + p = malloc(ndash * sizeof(unsigned char)); + if (!p) + return BadAlloc; + + pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; + if (offset != pGC->dashOffset) { + pGC->dashOffset = offset; + pGC->stateChanges |= GCDashOffset; + maskQ |= GCDashOffset; + } + + if (pGC->dash != DefaultDash) + free(pGC->dash); + pGC->numInDashList = ndash; + pGC->dash = p; + if (ndash & 1) { + pGC->numInDashList += ndash; + indash = pdash; + i = ndash; + while (i--) + *p++ = *indash++; + } + while (ndash--) + *p++ = *pdash++; + pGC->stateChanges |= GCDashList; + maskQ |= GCDashList; + + if (pGC->funcs->ChangeGC) + (*pGC->funcs->ChangeGC) (pGC, maskQ); + return Success; +} + +_X_EXPORT int +VerifyRectOrder(int nrects, xRectangle *prects, int ordering) +{ + xRectangle *prectP, *prectN; + + int i; + + switch (ordering) { + case Unsorted: + return CT_UNSORTED; + case YSorted: + if (nrects > 1) { + for (i = 1, prectP = prects, prectN = prects + 1; + i < nrects; i++, prectP++, prectN++) + if (prectN->y < prectP->y) + return -1; + } + return CT_YSORTED; + case YXSorted: + if (nrects > 1) { + for (i = 1, prectP = prects, prectN = prects + 1; + i < nrects; i++, prectP++, prectN++) + if ((prectN->y < prectP->y) || + ((prectN->y == prectP->y) && (prectN->x < prectP->x))) + return -1; + } + return CT_YXSORTED; + case YXBanded: + if (nrects > 1) { + for (i = 1, prectP = prects, prectN = prects + 1; + i < nrects; i++, prectP++, prectN++) + if ((prectN->y != prectP->y && + prectN->y < prectP->y + (int) prectP->height) || + ((prectN->y == prectP->y) && + (prectN->height != prectP->height || + prectN->x < prectP->x + (int) prectP->width))) + return -1; + } + return CT_YXBANDED; + } + return -1; +} + +_X_EXPORT int +SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects, + xRectangle *prects, int ordering) +{ + int newct, size; + + xRectangle *prectsNew; + + newct = VerifyRectOrder(nrects, prects, ordering); + if (newct < 0) + return (BadMatch); + size = nrects * sizeof(xRectangle); + prectsNew = malloc(size); + if (!prectsNew && size) + return BadAlloc; + + pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; + pGC->clipOrg.x = xOrigin; + pGC->stateChanges |= GCClipXOrigin; + + pGC->clipOrg.y = yOrigin; + pGC->stateChanges |= GCClipYOrigin; + + if (size) + memmove((char *) prectsNew, (char *) prects, size); + (*pGC->funcs->ChangeClip) (pGC, newct, (pointer) prectsNew, nrects); + if (pGC->funcs->ChangeGC) + (*pGC->funcs->ChangeGC) (pGC, + GCClipXOrigin | GCClipYOrigin | GCClipMask); + return Success; +} + +/* + sets reasonable defaults + if we can get a pre-allocated one, use it and mark it as used. + if we can't, create one out of whole cloth (The Velveteen GC -- if + you use it often enough it will become real.) +*/ +_X_EXPORT GCPtr +GetScratchGC(register unsigned depth, register ScreenPtr pScreen) +{ + int i; + + GCPtr pGC; + + for (i = 0; i <= pScreen->numDepths; i++) + if (pScreen->GCperDepth[i]->depth == depth && + !(pScreen->rgf & (1L << (i + 1))) + ) { + pScreen->rgf |= (1L << (i + 1)); + pGC = (pScreen->GCperDepth[i]); + + pGC->alu = GXcopy; + pGC->planemask = ~0; + pGC->serialNumber = 0; + pGC->fgPixel = 0; + pGC->bgPixel = 1; + pGC->lineWidth = 0; + pGC->lineStyle = LineSolid; + pGC->capStyle = CapButt; + pGC->joinStyle = JoinMiter; + pGC->fillStyle = FillSolid; + pGC->fillRule = EvenOddRule; + pGC->arcMode = ArcChord; + pGC->patOrg.x = 0; + pGC->patOrg.y = 0; + pGC->subWindowMode = ClipByChildren; + pGC->graphicsExposures = FALSE; + pGC->clipOrg.x = 0; + pGC->clipOrg.y = 0; + if (pGC->clientClipType != CT_NONE) + (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0); + pGC->stateChanges = (1 << (GCLastBit + 1)) - 1; + return pGC; + } + /* if we make it this far, need to roll our own */ + pGC = CreateScratchGC(pScreen, depth); + if (pGC) + pGC->graphicsExposures = FALSE; + return pGC; +} + +/* + if the gc to free is in the table of pre-existing ones, +mark it as available. + if not, free it for real +*/ +_X_EXPORT void +FreeScratchGC(register GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + + int i; + + for (i = 0; i <= pScreen->numDepths; i++) { + if (pScreen->GCperDepth[i] == pGC) { + pScreen->rgf &= ~(1L << (i + 1)); + return; + } + } + (void) FreeGC(pGC, (GContext) 0); +} diff --git a/dix/globals.c b/dix/globals.c new file mode 100644 index 0000000..6b17073 --- /dev/null +++ b/dix/globals.c @@ -0,0 +1,176 @@ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "windowstr.h" +#include "scrnintstr.h" +#include "input.h" +#include "dixfont.h" +#include "site.h" +#include "dixstruct.h" +#include "os.h" + +_X_EXPORT ScreenInfo screenInfo; + +KeybdCtrl defaultKeyboardControl = { + DEFAULT_KEYBOARD_CLICK, + DEFAULT_BELL, + DEFAULT_BELL_PITCH, + DEFAULT_BELL_DURATION, + DEFAULT_AUTOREPEAT, + DEFAULT_AUTOREPEATS, + DEFAULT_LEDS, + 0 +}; + +PtrCtrl defaultPointerControl = { + DEFAULT_PTR_NUMERATOR, + DEFAULT_PTR_DENOMINATOR, + DEFAULT_PTR_THRESHOLD, + 0 +}; + +_X_EXPORT ClientPtr clients[MAXCLIENTS]; +_X_EXPORT ClientPtr serverClient; +_X_EXPORT int currentMaxClients; /* current size of clients array */ + +_X_EXPORT long maxBigRequestSize = MAX_BIG_REQUEST_SIZE; + +_X_EXPORT WindowPtr WindowTable[MAXSCREENS]; + +_X_EXPORT unsigned long globalSerialNumber = 0; + +_X_EXPORT unsigned long serverGeneration = 0; + +/* these next four are initialized in main.c */ +_X_EXPORT CARD32 ScreenSaverTime; + +CARD32 ScreenSaverInterval; + +_X_EXPORT int ScreenSaverBlanking; + +int ScreenSaverAllowExposures; + +#ifdef DPMSExtension +# ifndef DEFAULT_STANDBY_TIME +# define DEFAULT_STANDBY_TIME DEFAULT_SCREEN_SAVER_TIME * 2 +# endif +# ifndef DEFAULT_SUSPEND_TIME +# define DEFAULT_SUSPEND_TIME DEFAULT_SCREEN_SAVER_TIME * 3 +# endif +# ifndef DEFAULT_OFF_TIME +# define DEFAULT_OFF_TIME DEFAULT_SCREEN_SAVER_TIME * 4 +# endif +# ifndef DEFAULT_DPMS_ENABLED +# define DEFAULT_DPMS_ENABLED TRUE +# endif + +_X_EXPORT CARD16 DPMSPowerLevel = 0; + +_X_EXPORT Bool DPMSEnabledSwitch = FALSE; /* these denote the DPMS command */ +_X_EXPORT Bool DPMSDisabledSwitch = FALSE; /* lind switch states */ +_X_EXPORT Bool DPMSCapableFlag = FALSE; + +_X_EXPORT CARD32 DPMSStandbyTime; +_X_EXPORT CARD32 DPMSSuspendTime; +_X_EXPORT CARD32 DPMSOffTime; + +_X_EXPORT Bool DPMSEnabled; +#endif + +CARD32 defaultScreenSaverTime = DEFAULT_SCREEN_SAVER_TIME; + +CARD32 defaultScreenSaverInterval = DEFAULT_SCREEN_SAVER_INTERVAL; + +int defaultScreenSaverBlanking = DEFAULT_SCREEN_SAVER_BLANKING; + +int defaultScreenSaverAllowExposures = DEFAULT_SCREEN_SAVER_EXPOSURES; + +#ifndef NOLOGOHACK +int logoScreenSaver = DEFAULT_LOGO_SCREEN_SAVER; +#endif + +#ifdef SCREENSAVER +Bool screenSaverSuspended = FALSE; +#endif + +char *defaultFontPath = COMPILEDDEFAULTFONTPATH; + +char *defaultTextFont = COMPILEDDEFAULTFONT; + +char *defaultCursorFont = COMPILEDCURSORFONT; + +char *defaultDisplayClass = COMPILEDDISPLAYCLASS; + +FontPtr defaultFont; /* not declared in dix.h to avoid including font.h in + every compilation of dix code */ +CursorPtr rootCursor; + +Bool blackRoot = FALSE; + +Bool whiteRoot = FALSE; + +ClientPtr requestingClient; /* XXX this should be obsolete now, remove? */ + +_X_EXPORT TimeStamp currentTime; + +_X_EXPORT TimeStamp lastDeviceEventTime; + +_X_EXPORT int defaultColorVisualClass = -1; + +_X_EXPORT int monitorResolution = 0; + +_X_EXPORT char *display; + +CARD32 TimeOutValue = DEFAULT_TIMEOUT * MILLI_PER_SECOND; + +DDXPointRec dixScreenOrigins[MAXSCREENS]; diff --git a/dix/glyphcurs.c b/dix/glyphcurs.c new file mode 100644 index 0000000..3278735 --- /dev/null +++ b/dix/glyphcurs.c @@ -0,0 +1,194 @@ +/************************************************************************ + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "misc.h" +#include +#include "dixfontstr.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "resource.h" +#include "dix.h" +#include "cursorstr.h" +#include "opaque.h" +#include "servermd.h" + +/* + get the bits out of the font in a portable way. to avoid +dealing with padding and such-like, we draw the glyph into +a bitmap, then read the bits out with GetImage, which +uses server-natural format. + since all screens return the same bitmap format, we'll just use +the first one we find. + the character origin lines up with the hotspot in the +cursor metrics. +*/ + +int +ServerBitsFromGlyph(FontPtr pfont, unsigned ch, register CursorMetricPtr cm, + unsigned char **ppbits) +{ + ScreenPtr pScreen; + + GCPtr pGC; + + xRectangle rect; + + PixmapPtr ppix; + + long nby; + + char *pbits; + + ChangeGCVal gcval[3]; + + unsigned char char2b[2]; + + /* turn glyph index into a protocol-format char2b */ + char2b[0] = (unsigned char) (ch >> 8); + char2b[1] = (unsigned char) (ch & 0xff); + + pScreen = screenInfo.screens[0]; + nby = BitmapBytePad(cm->width) * (long) cm->height; + pbits = malloc(nby); + if (!pbits) + return BadAlloc; + /* zeroing the (pad) bits seems to help some ddx cursor handling */ + bzero(pbits, nby); + + ppix = (PixmapPtr) (*pScreen->CreatePixmap) (pScreen, cm->width, + cm->height, 1); + pGC = GetScratchGC(1, pScreen); + if (!ppix || !pGC) { + if (ppix) + (*pScreen->DestroyPixmap) (ppix); + if (pGC) + FreeScratchGC(pGC); + free(pbits); + return BadAlloc; + } + + rect.x = 0; + rect.y = 0; + rect.width = cm->width; + rect.height = cm->height; + + /* fill the pixmap with 0 */ + gcval[0].val = GXcopy; + gcval[1].val = 0; + gcval[2].ptr = (pointer) pfont; + dixChangeGC(NullClient, pGC, GCFunction | GCForeground | GCFont, + NULL, gcval); + ValidateGC((DrawablePtr) ppix, pGC); + (*pGC->ops->PolyFillRect) ((DrawablePtr) ppix, pGC, 1, &rect); + + /* draw the glyph */ + gcval[0].val = 1; + dixChangeGC(NullClient, pGC, GCForeground, NULL, gcval); + ValidateGC((DrawablePtr) ppix, pGC); + (*pGC->ops->PolyText16) ((DrawablePtr) ppix, pGC, cm->xhot, cm->yhot, + 1, (unsigned short *) char2b); + (*pScreen->GetImage) ((DrawablePtr) ppix, 0, 0, cm->width, cm->height, + XYPixmap, 1, pbits); + *ppbits = (unsigned char *) pbits; + FreeScratchGC(pGC); + (*pScreen->DestroyPixmap) (ppix); + return Success; +} + +Bool +CursorMetricsFromGlyph(register FontPtr pfont, unsigned ch, + register CursorMetricPtr cm) +{ + CharInfoPtr pci; + + unsigned long nglyphs; + + CARD8 chs[2]; + + FontEncoding encoding; + + chs[0] = ch >> 8; + chs[1] = ch; + encoding = (FONTLASTROW(pfont) == 0) ? Linear16Bit : TwoD16Bit; + if (encoding == Linear16Bit) { + if (ch < pfont->info.firstCol || pfont->info.lastCol < ch) + return FALSE; + } + else { + if (chs[0] < pfont->info.firstRow || pfont->info.lastRow < chs[0]) + return FALSE; + if (chs[1] < pfont->info.firstCol || pfont->info.lastCol < chs[1]) + return FALSE; + } + (*pfont->get_glyphs) (pfont, 1, chs, encoding, &nglyphs, &pci); + if (nglyphs == 0) + return FALSE; + cm->width = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing; + cm->height = pci->metrics.descent + pci->metrics.ascent; + if (pci->metrics.leftSideBearing > 0) { + cm->width += pci->metrics.leftSideBearing; + cm->xhot = 0; + } + else { + cm->xhot = -pci->metrics.leftSideBearing; + if (pci->metrics.rightSideBearing < 0) + cm->width -= pci->metrics.rightSideBearing; + } + if (pci->metrics.ascent < 0) { + cm->height -= pci->metrics.ascent; + cm->yhot = 0; + } + else { + cm->yhot = pci->metrics.ascent; + if (pci->metrics.descent < 0) + cm->height -= pci->metrics.descent; + } + return TRUE; +} diff --git a/dix/grabs.c b/dix/grabs.c new file mode 100644 index 0000000..a21343c --- /dev/null +++ b/dix/grabs.c @@ -0,0 +1,404 @@ +/* + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include +#include "windowstr.h" +#include "inputstr.h" +#include "cursorstr.h" +#include "dixgrabs.h" + +#define BITMASK(i) (((Mask)1) << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +GrabPtr +CreateGrab(int client, DeviceIntPtr device, WindowPtr window, Mask eventMask, Bool ownerEvents, Bool keyboardMode, Bool pointerMode, DeviceIntPtr modDevice, unsigned short modifiers, int type, KeyCode keybut, /* key or button */ + WindowPtr confineTo, CursorPtr cursor) +{ + GrabPtr grab; + + grab = malloc(sizeof(GrabRec)); + if (!grab) + return (GrabPtr) NULL; + grab->resource = FakeClientID(client); + grab->device = device; + grab->coreGrab = ((device == inputInfo.keyboard) || + (device == inputInfo.pointer)); + grab->window = window; + grab->eventMask = eventMask; + grab->ownerEvents = ownerEvents; + grab->keyboardMode = keyboardMode; + grab->pointerMode = pointerMode; + grab->modifiersDetail.exact = modifiers; + grab->modifiersDetail.pMask = NULL; + grab->modifierDevice = modDevice; + grab->coreMods = ((modDevice == inputInfo.keyboard) || + (modDevice == inputInfo.pointer)); + grab->type = type; + grab->detail.exact = keybut; + grab->detail.pMask = NULL; + grab->confineTo = confineTo; + grab->cursor = cursor; + if (cursor) + cursor->refcnt++; + return grab; + +} + +static void +FreeGrab(GrabPtr pGrab) +{ + if (pGrab->modifiersDetail.pMask != NULL) + free(pGrab->modifiersDetail.pMask); + + if (pGrab->detail.pMask != NULL) + free(pGrab->detail.pMask); + + if (pGrab->cursor) + FreeCursor(pGrab->cursor, (Cursor) 0); + + free(pGrab); +} + +int +DeletePassiveGrab(pointer value, XID id) +{ + GrabPtr g, prev; + + GrabPtr pGrab = (GrabPtr) value; + + /* it is OK if the grab isn't found */ + prev = 0; + for (g = (wPassiveGrabs(pGrab->window)); g; g = g->next) { + if (pGrab == g) { + if (prev) + prev->next = g->next; + else if (!(pGrab->window->optional->passiveGrabs = g->next)) + CheckWindowOptionalNeed(pGrab->window); + break; + } + prev = g; + } + FreeGrab(pGrab); + return Success; +} + +static Mask * +DeleteDetailFromMask(Mask *pDetailMask, unsigned short detail) +{ + Mask *mask; + + int i; + + mask = malloc(sizeof(Mask) * MasksPerDetailMask); + if (mask) { + if (pDetailMask) + for (i = 0; i < MasksPerDetailMask; i++) + mask[i] = pDetailMask[i]; + else + for (i = 0; i < MasksPerDetailMask; i++) + mask[i] = ~0L; + BITCLEAR(mask, detail); + } + return mask; +} + +static Bool +IsInGrabMask(DetailRec firstDetail, + DetailRec secondDetail, unsigned short exception) +{ + if (firstDetail.exact == exception) { + if (firstDetail.pMask == NULL) + return TRUE; + + /* (at present) never called with two non-null pMasks */ + if (secondDetail.exact == exception) + return FALSE; + + if (GETBIT(firstDetail.pMask, secondDetail.exact)) + return TRUE; + } + + return FALSE; +} + +static Bool +IdenticalExactDetails(unsigned short firstExact, + unsigned short secondExact, unsigned short exception) +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + +static Bool +DetailSupersedesSecond(DetailRec firstDetail, + DetailRec secondDetail, unsigned short exception) +{ + if (IsInGrabMask(firstDetail, secondDetail, exception)) + return TRUE; + + if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, exception)) + return TRUE; + + return FALSE; +} + +static Bool +GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + (unsigned short) AnyModifier)) + return FALSE; + + if (DetailSupersedesSecond(pFirstGrab->detail, + pSecondGrab->detail, (unsigned short) AnyKey)) + return TRUE; + + return FALSE; +} + +Bool +GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +{ + if ((pFirstGrab->device != pSecondGrab->device) || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || + (pFirstGrab->type != pSecondGrab->type)) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, + (unsigned short) AnyKey) + && + DetailSupersedesSecond(pFirstGrab->modifiersDetail, + pSecondGrab->modifiersDetail, + (unsigned short) AnyModifier)) + return TRUE; + + if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, + (unsigned short) AnyKey) + && + DetailSupersedesSecond(pSecondGrab->modifiersDetail, + pFirstGrab->modifiersDetail, + (unsigned short) AnyModifier)) + return TRUE; + + return FALSE; +} + +int +AddPassiveGrabToList(GrabPtr pGrab) +{ + GrabPtr grab; + + for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) { + if (GrabMatchesSecond(pGrab, grab)) { + if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) { + FreeGrab(pGrab); + return BadAccess; + } + } + } + + if (!pGrab->window->optional && !MakeWindowOptional(pGrab->window)) { + FreeGrab(pGrab); + return BadAlloc; + } + pGrab->next = pGrab->window->optional->passiveGrabs; + pGrab->window->optional->passiveGrabs = pGrab; + if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (pointer) pGrab)) + return Success; + return BadAlloc; +} + +/* the following is kinda complicated, because we need to be able to back out + * if any allocation fails + */ + +Bool +DeletePassiveGrabFromList(GrabPtr pMinuendGrab) +{ + GrabPtr grab; + + GrabPtr *deletes, *adds; + + Mask ***updates, **details; + + int i, ndels, nadds, nups; + + Bool ok; + +#define UPDATE(mask,exact) \ + if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ + ok = FALSE; \ + else \ + updates[nups++] = &(mask) + + i = 0; + for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) + i++; + if (!i) + return TRUE; + deletes = (GrabPtr *) ALLOCATE_LOCAL(i * sizeof(GrabPtr)); + adds = (GrabPtr *) ALLOCATE_LOCAL(i * sizeof(GrabPtr)); + updates = (Mask ***) ALLOCATE_LOCAL(i * sizeof(Mask **)); + details = (Mask **) ALLOCATE_LOCAL(i * sizeof(Mask *)); + if (!deletes || !adds || !updates || !details) { + if (details) + DEALLOCATE_LOCAL(details); + if (updates) + DEALLOCATE_LOCAL(updates); + if (adds) + DEALLOCATE_LOCAL(adds); + if (deletes) + DEALLOCATE_LOCAL(deletes); + return FALSE; + } + ndels = nadds = nups = 0; + ok = TRUE; + for (grab = wPassiveGrabs(pMinuendGrab->window); + grab && ok; grab = grab->next) { + if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) + || !GrabMatchesSecond(grab, pMinuendGrab)) + continue; + if (GrabSupersedesSecond(pMinuendGrab, grab)) { + deletes[ndels++] = grab; + } + else if ((grab->detail.exact == AnyKey) + && (grab->modifiersDetail.exact != AnyModifier)) { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + else if ((grab->modifiersDetail.exact == AnyModifier) + && (grab->detail.exact != AnyKey)) { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else if ((pMinuendGrab->detail.exact != AnyKey) + && (pMinuendGrab->modifiersDetail.exact != AnyModifier)) { + GrabPtr pNewGrab; + + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + + pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, + grab->window, (Mask) grab->eventMask, + (Bool) grab->ownerEvents, + (Bool) grab->keyboardMode, + (Bool) grab->pointerMode, + grab->modifierDevice, + AnyModifier, (int) grab->type, + pMinuendGrab->detail.exact, + grab->confineTo, grab->cursor); + if (!pNewGrab) + ok = FALSE; + else if (!(pNewGrab->modifiersDetail.pMask = + DeleteDetailFromMask(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail. + exact)) + || (!pNewGrab->window->optional && + !MakeWindowOptional(pNewGrab->window))) { + FreeGrab(pNewGrab); + ok = FALSE; + } + else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, + (pointer) pNewGrab)) + ok = FALSE; + else + adds[nadds++] = pNewGrab; + } + else if (pMinuendGrab->detail.exact == AnyKey) { + UPDATE(grab->modifiersDetail.pMask, + pMinuendGrab->modifiersDetail.exact); + } + else { + UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); + } + } + + if (!ok) { + for (i = 0; i < nadds; i++) + FreeResource(adds[i]->resource, RT_NONE); + for (i = 0; i < nups; i++) + free(details[i]); + } + else { + for (i = 0; i < ndels; i++) + FreeResource(deletes[i]->resource, RT_NONE); + for (i = 0; i < nadds; i++) { + grab = adds[i]; + grab->next = grab->window->optional->passiveGrabs; + grab->window->optional->passiveGrabs = grab; + } + for (i = 0; i < nups; i++) { + free(*updates[i]); + *updates[i] = details[i]; + } + } + DEALLOCATE_LOCAL(details); + DEALLOCATE_LOCAL(updates); + DEALLOCATE_LOCAL(adds); + DEALLOCATE_LOCAL(deletes); + return ok; + +#undef UPDATE +} diff --git a/dix/initatoms.c b/dix/initatoms.c new file mode 100644 index 0000000..110e0be --- /dev/null +++ b/dix/initatoms.c @@ -0,0 +1,153 @@ +/* THIS IS A GENERATED FILE + * + * Do not change! Changing this file implies a protocol change! + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "dix.h" +void +MakePredeclaredAtoms() +{ + if (MakeAtom("PRIMARY", 7, 1) != XA_PRIMARY) + AtomError(); + if (MakeAtom("SECONDARY", 9, 1) != XA_SECONDARY) + AtomError(); + if (MakeAtom("ARC", 3, 1) != XA_ARC) + AtomError(); + if (MakeAtom("ATOM", 4, 1) != XA_ATOM) + AtomError(); + if (MakeAtom("BITMAP", 6, 1) != XA_BITMAP) + AtomError(); + if (MakeAtom("CARDINAL", 8, 1) != XA_CARDINAL) + AtomError(); + if (MakeAtom("COLORMAP", 8, 1) != XA_COLORMAP) + AtomError(); + if (MakeAtom("CURSOR", 6, 1) != XA_CURSOR) + AtomError(); + if (MakeAtom("CUT_BUFFER0", 11, 1) != XA_CUT_BUFFER0) + AtomError(); + if (MakeAtom("CUT_BUFFER1", 11, 1) != XA_CUT_BUFFER1) + AtomError(); + if (MakeAtom("CUT_BUFFER2", 11, 1) != XA_CUT_BUFFER2) + AtomError(); + if (MakeAtom("CUT_BUFFER3", 11, 1) != XA_CUT_BUFFER3) + AtomError(); + if (MakeAtom("CUT_BUFFER4", 11, 1) != XA_CUT_BUFFER4) + AtomError(); + if (MakeAtom("CUT_BUFFER5", 11, 1) != XA_CUT_BUFFER5) + AtomError(); + if (MakeAtom("CUT_BUFFER6", 11, 1) != XA_CUT_BUFFER6) + AtomError(); + if (MakeAtom("CUT_BUFFER7", 11, 1) != XA_CUT_BUFFER7) + AtomError(); + if (MakeAtom("DRAWABLE", 8, 1) != XA_DRAWABLE) + AtomError(); + if (MakeAtom("FONT", 4, 1) != XA_FONT) + AtomError(); + if (MakeAtom("INTEGER", 7, 1) != XA_INTEGER) + AtomError(); + if (MakeAtom("PIXMAP", 6, 1) != XA_PIXMAP) + AtomError(); + if (MakeAtom("POINT", 5, 1) != XA_POINT) + AtomError(); + if (MakeAtom("RECTANGLE", 9, 1) != XA_RECTANGLE) + AtomError(); + if (MakeAtom("RESOURCE_MANAGER", 16, 1) != XA_RESOURCE_MANAGER) + AtomError(); + if (MakeAtom("RGB_COLOR_MAP", 13, 1) != XA_RGB_COLOR_MAP) + AtomError(); + if (MakeAtom("RGB_BEST_MAP", 12, 1) != XA_RGB_BEST_MAP) + AtomError(); + if (MakeAtom("RGB_BLUE_MAP", 12, 1) != XA_RGB_BLUE_MAP) + AtomError(); + if (MakeAtom("RGB_DEFAULT_MAP", 15, 1) != XA_RGB_DEFAULT_MAP) + AtomError(); + if (MakeAtom("RGB_GRAY_MAP", 12, 1) != XA_RGB_GRAY_MAP) + AtomError(); + if (MakeAtom("RGB_GREEN_MAP", 13, 1) != XA_RGB_GREEN_MAP) + AtomError(); + if (MakeAtom("RGB_RED_MAP", 11, 1) != XA_RGB_RED_MAP) + AtomError(); + if (MakeAtom("STRING", 6, 1) != XA_STRING) + AtomError(); + if (MakeAtom("VISUALID", 8, 1) != XA_VISUALID) + AtomError(); + if (MakeAtom("WINDOW", 6, 1) != XA_WINDOW) + AtomError(); + if (MakeAtom("WM_COMMAND", 10, 1) != XA_WM_COMMAND) + AtomError(); + if (MakeAtom("WM_HINTS", 8, 1) != XA_WM_HINTS) + AtomError(); + if (MakeAtom("WM_CLIENT_MACHINE", 17, 1) != XA_WM_CLIENT_MACHINE) + AtomError(); + if (MakeAtom("WM_ICON_NAME", 12, 1) != XA_WM_ICON_NAME) + AtomError(); + if (MakeAtom("WM_ICON_SIZE", 12, 1) != XA_WM_ICON_SIZE) + AtomError(); + if (MakeAtom("WM_NAME", 7, 1) != XA_WM_NAME) + AtomError(); + if (MakeAtom("WM_NORMAL_HINTS", 15, 1) != XA_WM_NORMAL_HINTS) + AtomError(); + if (MakeAtom("WM_SIZE_HINTS", 13, 1) != XA_WM_SIZE_HINTS) + AtomError(); + if (MakeAtom("WM_ZOOM_HINTS", 13, 1) != XA_WM_ZOOM_HINTS) + AtomError(); + if (MakeAtom("MIN_SPACE", 9, 1) != XA_MIN_SPACE) + AtomError(); + if (MakeAtom("NORM_SPACE", 10, 1) != XA_NORM_SPACE) + AtomError(); + if (MakeAtom("MAX_SPACE", 9, 1) != XA_MAX_SPACE) + AtomError(); + if (MakeAtom("END_SPACE", 9, 1) != XA_END_SPACE) + AtomError(); + if (MakeAtom("SUPERSCRIPT_X", 13, 1) != XA_SUPERSCRIPT_X) + AtomError(); + if (MakeAtom("SUPERSCRIPT_Y", 13, 1) != XA_SUPERSCRIPT_Y) + AtomError(); + if (MakeAtom("SUBSCRIPT_X", 11, 1) != XA_SUBSCRIPT_X) + AtomError(); + if (MakeAtom("SUBSCRIPT_Y", 11, 1) != XA_SUBSCRIPT_Y) + AtomError(); + if (MakeAtom("UNDERLINE_POSITION", 18, 1) != XA_UNDERLINE_POSITION) + AtomError(); + if (MakeAtom("UNDERLINE_THICKNESS", 19, 1) != XA_UNDERLINE_THICKNESS) + AtomError(); + if (MakeAtom("STRIKEOUT_ASCENT", 16, 1) != XA_STRIKEOUT_ASCENT) + AtomError(); + if (MakeAtom("STRIKEOUT_DESCENT", 17, 1) != XA_STRIKEOUT_DESCENT) + AtomError(); + if (MakeAtom("ITALIC_ANGLE", 12, 1) != XA_ITALIC_ANGLE) + AtomError(); + if (MakeAtom("X_HEIGHT", 8, 1) != XA_X_HEIGHT) + AtomError(); + if (MakeAtom("QUAD_WIDTH", 10, 1) != XA_QUAD_WIDTH) + AtomError(); + if (MakeAtom("WEIGHT", 6, 1) != XA_WEIGHT) + AtomError(); + if (MakeAtom("POINT_SIZE", 10, 1) != XA_POINT_SIZE) + AtomError(); + if (MakeAtom("RESOLUTION", 10, 1) != XA_RESOLUTION) + AtomError(); + if (MakeAtom("COPYRIGHT", 9, 1) != XA_COPYRIGHT) + AtomError(); + if (MakeAtom("NOTICE", 6, 1) != XA_NOTICE) + AtomError(); + if (MakeAtom("FONT_NAME", 9, 1) != XA_FONT_NAME) + AtomError(); + if (MakeAtom("FAMILY_NAME", 11, 1) != XA_FAMILY_NAME) + AtomError(); + if (MakeAtom("FULL_NAME", 9, 1) != XA_FULL_NAME) + AtomError(); + if (MakeAtom("CAP_HEIGHT", 10, 1) != XA_CAP_HEIGHT) + AtomError(); + if (MakeAtom("WM_CLASS", 8, 1) != XA_WM_CLASS) + AtomError(); + if (MakeAtom("WM_TRANSIENT_FOR", 16, 1) != XA_WM_TRANSIENT_FOR) + AtomError(); +} diff --git a/dix/main.c b/dix/main.c new file mode 100644 index 0000000..a2c3a25 --- /dev/null +++ b/dix/main.c @@ -0,0 +1,661 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +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 both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include /* for unistd.h */ +#include +#include "scrnintstr.h" +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "extension.h" +#include "colormap.h" +#include "colormapst.h" +#include "cursorstr.h" +#include +#include "opaque.h" +#include "servermd.h" +#include "site.h" +#include "dixfont.h" +#include "extnsionst.h" +#include "dixevents.h" /* InitEvents() */ + +#ifdef DPMSExtension +#define DPMS_SERVER +#include +#include "dpmsproc.h" +#endif + +extern int InitClientPrivates(ClientPtr client); + +extern void Dispatch(void); + +char *ConnectionInfo; + +xConnSetupPrefix connSetupPrefix; + +extern FontPtr defaultFont; + +extern int screenPrivateCount; + +extern Bool CreateGCperDepthArray(void); + +static +Bool CreateConnectionBlock(void); + +static void FreeScreen(ScreenPtr); + +_X_EXPORT PaddingInfo PixmapWidthPaddingInfo[33]; + +int connBlockScreenStart; + +_X_EXPORT void +NotImplemented(xEvent *from, xEvent *to) +{ + FatalError("Not implemented"); +} + +/* + * Dummy entry for ReplySwapVector[] + */ + +void +ReplyNotSwappd(ClientPtr pClient, int size, void *pbuf) +{ + FatalError("Not implemented"); +} + +/* + * This array encodes the answer to the question "what is the log base 2 + * of the number of pixels that fit in a scanline pad unit?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int answer[6][4] = { + /* pad pad pad pad */ + /* 8 16 32 64 */ + + {3, 4, 5, 6}, /* 1 bit per pixel */ + {1, 2, 3, 4}, /* 4 bits per pixel */ + {0, 1, 2, 3}, /* 8 bits per pixel */ + {~0, 0, 1, 2}, /* 16 bits per pixel */ + {~0, ~0, 0, 1}, /* 24 bits per pixel */ + {~0, ~0, 0, 1} /* 32 bits per pixel */ +}; + +/* + * This array gives the answer to the question "what is the first index for + * the answer array above given the number of bits per pixel?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int indexForBitsPerPixel[33] = { + ~0, 0, ~0, ~0, /* 1 bit per pixel */ + 1, ~0, ~0, ~0, /* 4 bits per pixel */ + 2, ~0, ~0, ~0, /* 8 bits per pixel */ + ~0, ~0, ~0, ~0, + 3, ~0, ~0, ~0, /* 16 bits per pixel */ + ~0, ~0, ~0, ~0, + 4, ~0, ~0, ~0, /* 24 bits per pixel */ + ~0, ~0, ~0, ~0, + 5 /* 32 bits per pixel */ +}; + +/* + * This array gives the bytesperPixel value for cases where the number + * of bits per pixel is a multiple of 8 but not a power of 2. + */ +static int answerBytesPerPixel[33] = { + ~0, 0, ~0, ~0, /* 1 bit per pixel */ + 0, ~0, ~0, ~0, /* 4 bits per pixel */ + 0, ~0, ~0, ~0, /* 8 bits per pixel */ + ~0, ~0, ~0, ~0, + 0, ~0, ~0, ~0, /* 16 bits per pixel */ + ~0, ~0, ~0, ~0, + 3, ~0, ~0, ~0, /* 24 bits per pixel */ + ~0, ~0, ~0, ~0, + 0 /* 32 bits per pixel */ +}; + +/* + * This array gives the answer to the question "what is the second index for + * the answer array above given the number of bits per scanline pad unit?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int indexForScanlinePad[65] = { + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 0, ~0, ~0, ~0, /* 8 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + 1, ~0, ~0, ~0, /* 16 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 2, ~0, ~0, ~0, /* 32 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 3 /* 64 bits per scanline pad unit */ +}; + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int +main(int argc, char *argv[], char *envp[]) +{ + int i; + + char *xauthfile; + + HWEventQueueType alwaysCheckForInput[2]; + + display = "0"; + + /* Quartz support on Mac OS X requires that the Cocoa event loop be in + * the main thread. This allows the X server main to be called again + * from another thread. */ + + CheckUserParameters(argc, argv, envp); + + CheckUserAuthorization(); + + + InitConnectionLimits(); + + /* prep X authority file from environment; this can be overriden by a + * command line option */ + xauthfile = getenv("XAUTHORITY"); + if (xauthfile) + InitAuthorization(xauthfile); + ProcessCommandLine(argc, argv); + + alwaysCheckForInput[0] = 0; + alwaysCheckForInput[1] = 1; + while (1) { + serverGeneration++; + ScreenSaverTime = defaultScreenSaverTime; + ScreenSaverInterval = defaultScreenSaverInterval; + ScreenSaverBlanking = defaultScreenSaverBlanking; + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; +#ifdef DPMSExtension + DPMSStandbyTime = DEFAULT_SCREEN_SAVER_TIME; + DPMSSuspendTime = DEFAULT_SCREEN_SAVER_TIME; + DPMSOffTime = DEFAULT_SCREEN_SAVER_TIME; + DPMSEnabled = TRUE; + DPMSPowerLevel = 0; +#endif + InitBlockAndWakeupHandlers(); + /* Perform any operating system dependent initializations you'd like */ + OsInit(); + if (serverGeneration == 1) { + CreateWellKnownSockets(); + for (i = 1; i < MAXCLIENTS; i++) + clients[i] = NullClient; + serverClient = malloc(sizeof(ClientRec)); + if (!serverClient) + FatalError("couldn't create server client"); + InitClient(serverClient, 0, (pointer) NULL); + } + else + ResetWellKnownSockets(); + clients[0] = serverClient; + currentMaxClients = 1; + + if (!InitClientResources(serverClient)) /* for root resources */ + FatalError("couldn't init server resources"); + + SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]); + screenInfo.numScreens = 0; + + InitAtoms(); + InitEvents(); + InitGlyphCaching(); + ResetExtensionPrivates(); + ResetClientPrivates(); + ResetScreenPrivates(); + ResetWindowPrivates(); + ResetGCPrivates(); + ResetPixmapPrivates(); + ResetColormapPrivates(); + ResetFontPrivateIndex(); + ResetDevicePrivateIndex(); + InitCallbackManager(); + InitVisualWrap(); + InitOutput(&screenInfo, argc, argv); + + if (screenInfo.numScreens < 1) + FatalError("no screens found"); + InitExtensions(argc, argv); + if (!InitClientPrivates(serverClient)) + FatalError("failed to allocate serverClient devprivates"); + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + + if (!CreateScratchPixmapsForScreen(i)) + FatalError("failed to create scratch pixmaps"); + if (pScreen->CreateScreenResources && + !(*pScreen->CreateScreenResources) (pScreen)) + FatalError("failed to create screen resources"); + if (!CreateGCperDepth(i)) + FatalError("failed to create scratch GCs"); + if (!CreateDefaultStipple(i)) + FatalError("failed to create default stipple"); + if (!CreateRootWindow(pScreen)) + FatalError("failed to create root window"); + } + InitInput(argc, argv); + if (InitAndStartDevices() != Success) + FatalError("failed to initialize core devices"); + + InitFonts(); + if (SetDefaultFontPath(defaultFontPath) != Success) + ErrorF("failed to set default font path '%s'", defaultFontPath); + if (!SetDefaultFont(defaultTextFont)) + FatalError("could not open default font '%s'", defaultTextFont); + if (!(rootCursor = CreateRootCursor(defaultCursorFont, 0))) + FatalError("could not open default cursor font '%s'", + defaultCursorFont); +#ifdef DPMSExtension + /* check all screens, looking for DPMS Capabilities */ + DPMSCapableFlag = DPMSSupported(); + if (!DPMSCapableFlag) + DPMSEnabled = FALSE; +#endif + + + for (i = 0; i < screenInfo.numScreens; i++) + InitRootWindow(WindowTable[i]); + DefineInitialRootWindow(WindowTable[0]); + SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset); + + { + if (!CreateConnectionBlock()) + FatalError("could not create connection block info"); + } + + Dispatch(); + + /* Now free up whatever must be freed */ + if (screenIsSaved == SCREEN_SAVER_ON) + SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset); + FreeScreenSaverTimer(); + CloseDownExtensions(); + + FreeAllResources(); + + memset(WindowTable, 0, sizeof(WindowTable)); + CloseDownDevices(); + for (i = screenInfo.numScreens - 1; i >= 0; i--) { + FreeScratchPixmapsForScreen(i); + FreeGCperDepth(i); + FreeDefaultStipple(i); + (*screenInfo.screens[i]->CloseScreen) (i, screenInfo.screens[i]); + FreeScreen(screenInfo.screens[i]); + screenInfo.numScreens = i; + } + CloseDownEvents(); + FreeFonts(); + + free(serverClient->devPrivates); + serverClient->devPrivates = NULL; + + if (dispatchException & DE_TERMINATE) { + CloseWellKnownConnections(); + } + + OsCleanup((dispatchException & DE_TERMINATE) != 0); + + if (dispatchException & DE_TERMINATE) { + ddxGiveUp(); + break; + } + + free(ConnectionInfo); + ConnectionInfo = NULL; + } + return (0); +} + +static const int VendorRelease = VENDOR_RELEASE; +static const char * const VendorString = VENDOR_STRING; + +static const int padlength[4] = { 0, 3, 2, 1 }; + +static + Bool +CreateConnectionBlock() +{ + xConnSetup setup; + xWindowRoot root; + xDepth depth; + xVisualType visual; + xPixmapFormat format; + unsigned long vid; + int i, j, k, lenofblock, sizesofar = 0; + char *pBuf; + + memset(&setup, 0, sizeof(xConnSetup)); + + /* Leave off the ridBase and ridMask, these must be sent with + connection */ + + setup.release = VendorRelease; + /* + * per-server image and bitmap parameters are defined in Xmd.h + */ + setup.imageByteOrder = screenInfo.imageByteOrder; + + setup.bitmapScanlineUnit = screenInfo.bitmapScanlineUnit; + setup.bitmapScanlinePad = screenInfo.bitmapScanlinePad; + + setup.bitmapBitOrder = screenInfo.bitmapBitOrder; + setup.motionBufferSize = NumMotionEvents(); + setup.numRoots = screenInfo.numScreens; + setup.nbytesVendor = strlen(VendorString); + setup.numFormats = screenInfo.numPixmapFormats; + setup.maxRequestSize = MAX_REQUEST_SIZE; + QueryMinMaxKeyCodes(&setup.minKeyCode, &setup.maxKeyCode); + + lenofblock = sizeof(xConnSetup) + + ((setup.nbytesVendor + 3) & ~3) + + (setup.numFormats * sizeof(xPixmapFormat)) + + (setup.numRoots * sizeof(xWindowRoot)); + ConnectionInfo = malloc(lenofblock); + if (!ConnectionInfo) + return FALSE; + + memmove(ConnectionInfo, (char *) &setup, sizeof(xConnSetup)); + sizesofar = sizeof(xConnSetup); + pBuf = ConnectionInfo + sizeof(xConnSetup); + + memmove(pBuf, VendorString, (int) setup.nbytesVendor); + sizesofar += setup.nbytesVendor; + pBuf += setup.nbytesVendor; + i = padlength[setup.nbytesVendor & 3]; + sizesofar += i; + while (--i >= 0) + *pBuf++ = 0; + + memset(&format, 0, sizeof(xPixmapFormat)); + for (i = 0; i < screenInfo.numPixmapFormats; i++) { + format.depth = screenInfo.formats[i].depth; + format.bitsPerPixel = screenInfo.formats[i].bitsPerPixel; + format.scanLinePad = screenInfo.formats[i].scanlinePad; + memmove(pBuf, (char *) &format, sizeof(xPixmapFormat)); + pBuf += sizeof(xPixmapFormat); + sizesofar += sizeof(xPixmapFormat); + } + + connBlockScreenStart = sizesofar; + memset(&depth, 0, sizeof(xDepth)); + memset(&visual, 0, sizeof(xVisualType)); + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen; + DepthPtr pDepth; + VisualPtr pVisual; + + pScreen = screenInfo.screens[i]; + root.windowId = WindowTable[i]->drawable.id; + root.defaultColormap = pScreen->defColormap; + root.whitePixel = pScreen->whitePixel; + root.blackPixel = pScreen->blackPixel; + root.currentInputMask = 0; /* filled in when sent */ + root.pixWidth = pScreen->width; + root.pixHeight = pScreen->height; + root.mmWidth = pScreen->mmWidth; + root.mmHeight = pScreen->mmHeight; + root.minInstalledMaps = pScreen->minInstalledCmaps; + root.maxInstalledMaps = pScreen->maxInstalledCmaps; + root.rootVisualID = pScreen->rootVisual; + root.backingStore = pScreen->backingStoreSupport; + root.saveUnders = FALSE; + root.rootDepth = pScreen->rootDepth; + root.nDepths = pScreen->numDepths; + memmove(pBuf, (char *) &root, sizeof(xWindowRoot)); + sizesofar += sizeof(xWindowRoot); + pBuf += sizeof(xWindowRoot); + + pDepth = pScreen->allowedDepths; + for (j = 0; j < pScreen->numDepths; j++, pDepth++) { + lenofblock += sizeof(xDepth) + + (pDepth->numVids * sizeof(xVisualType)); + pBuf = (char *) realloc(ConnectionInfo, lenofblock); + if (!pBuf) { + free(ConnectionInfo); + return FALSE; + } + ConnectionInfo = pBuf; + pBuf += sizesofar; + depth.depth = pDepth->depth; + depth.nVisuals = pDepth->numVids; + memmove(pBuf, (char *) &depth, sizeof(xDepth)); + pBuf += sizeof(xDepth); + sizesofar += sizeof(xDepth); + for (k = 0; k < pDepth->numVids; k++) { + vid = pDepth->vids[k]; + for (pVisual = pScreen->visuals; + pVisual->vid != vid; pVisual++); + visual.visualID = vid; + visual.class = pVisual->class; + visual.bitsPerRGB = pVisual->bitsPerRGBValue; + visual.colormapEntries = pVisual->ColormapEntries; + visual.redMask = pVisual->redMask; + visual.greenMask = pVisual->greenMask; + visual.blueMask = pVisual->blueMask; + memmove(pBuf, (char *) &visual, sizeof(xVisualType)); + pBuf += sizeof(xVisualType); + sizesofar += sizeof(xVisualType); + } + } + } + connSetupPrefix.success = xTrue; + connSetupPrefix.length = lenofblock / 4; + connSetupPrefix.majorVersion = X_PROTOCOL; + connSetupPrefix.minorVersion = X_PROTOCOL_REVISION; + return TRUE; +} + +/* + grow the array of screenRecs if necessary. + call the device-supplied initialization